//UsrAI.h
//UsrAI.h
#ifndef USRAI_H
#define USRAI_H

#include "AI.h"
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <ctime>
#include <unordered_set>
#include <string>
#include <queue> // Added for std::queue

extern tagGame tagUsrGame;
extern ins UsrIns;

#ifndef MAPPATTERN_SHALLOWS
#define MAPPATTERN_SHALLOWS 3
#endif

class UsrAI : public AI
{
public:
    // Game stage enumeration
    enum GameStage {
        STAGE_INITIAL,                  // Initial stage
        STAGE_BUILD_HOUSES,             // House building stage
        STAGE_POPULATION_GROWTH,        // Population growth stage
        STAGE_COLLECT_RESOURCES,        // Resource collection stage
        STAGE_BUILD_REQUIRED_BUILDINGS, // Build required buildings stage (docks and stocks)
        STAGE_UPGRADE_AGE,              // Age upgrade stage
        STAGE_BUILD_FISHING_BOAT,       // Fishing boat building stage
        STAGE_AFTER_UPGRADE,            // New stage: tasks after upgrading to Tool Age
        STAGE_BUILD_WARSHIPS,           // New stage: produce warships
        STAGE_EXPLORE                   // New stage: warships explore unknown areas
    };
    static bool villagersAssigned; // Whether villagers have been assigned tasks

    static tagInfo prevInfo; // Game information from the previous frame
    static int center_x, center_y; // Town Center coordinates
    static bool centerInitialized; // Whether the Town Center has been initialized
    static std::set<std::pair<int, int>> occupiedPositions; // Occupied or planned map positions

    static int houseCount; // Number of houses built
    static int housesUnderConstruction; // Number of houses under construction
    static const int TARGET_HOUSES = 4; // Target number of houses
    static GameStage currentStage; // Current game stage
    static int searchRadius; // Search radius
    static int lastHouseX, lastHouseY; // Position of the last built house
    static int houseBuilderSN; // Serial number of the house builder

    static int targetPopulation; // Target population
    static time_t lastVillagerProductionTime; // Time of last villager production
    static bool buildingHousesInProgressInPopulationStage; // Whether houses are being built in the population growth stage

    static bool stockBuilt; // Whether a stock building has been built
    static bool dockBuilt; // Whether a dock has been built (at least one completed)
    static bool fishingBoatBuilt; // Whether fishing boats have been built (reached target quantity)
    static bool ageUpgraded; // Whether the age has been upgraded
    static int dockBuilderSN; // Serial number of the dock builder
    static bool dockBuilderReserved; // Whether the dock builder is reserved
    static bool dockConstructionStarted; // Whether dock construction has started
    static int totalDocksPresent; // Total number of docks on the map (including those under construction)
    static int completedDocksCount; // Number of completed docks
    static const int TARGET_DOCKS_NUM = 2; // Target number of docks

    static int fishingBoatCount; // Number of fishing boats
    static const int TARGET_FISHING_BOATS = 4; // Target number of fishing boats
    static const int TARGET_BOATS_PER_DOCK = 2; // Target number of fishing boats per dock
    static std::map<int, int> dockFishingBoatCount; // Number of fishing boats produced by each dock

    // New static variables for warship production and exploration
    static int warshipCount; // Number of warships
    static const int TARGET_WARSHIPS = 10; // Target total number of warships
    static const int TARGET_WARSHIPS_PER_DOCK = 5; // Target number of warships per dock
    static std::map<int, int> dockWarshipCount; // Number of warships produced by each dock

    // New static variables for warship fleets and targets
    static std::vector<std::vector<int>> warshipFleets; // Stores SNs of warships in each fleet
    static std::map<int, std::pair<int, int>> fleetExplorationTargets; // Exploration target coordinates for each fleet (key is fleet index)
    static std::map<int, int> fleetAttackTargetsSN; // Attack target SN for each fleet (key is fleet index)
    static std::unordered_set<int> assignedWarships; // Tracks which warships have been assigned to fleets
    static bool fleetsFormed; // New: Whether warship fleets have been initially formed

    static int foundDockX; // X-coordinate of the found dock position
    static int foundDockY; // Y-coordinate of the found dock position
    static bool dockPositionFound; // Whether a dock position has been found

    static std::vector<std::pair<int, int>> fishPositions; // Fish resource positions
    static bool fishPositionsInitialized; // Whether fish resource positions have been initialized
    static std::unordered_set<int> ordinaryVillagers; // Set of serial numbers for ordinary villagers

    // New static variables for post-Tool Age stage
    static int villagersToProduceAfterUpgrade; // Number of villagers to produce after upgrade
    static int villagersProducedAfterUpgrade;  // Number of villagers already produced after upgrade
    static int existingStocksAtUpgrade;        // Number of existing stocks at the time of upgrade
    static const int TARGET_TOTAL_STOCKS = 2; // New: Target total number of stocks

    // New static variables for dedicated Tool Age builder
    static int toolAgeBuilderSN;        // Serial number of the dedicated Tool Age builder
    static bool toolAgeBuilderAssigned; // Whether the dedicated builder is assigned
    static int housesToBuildAfterUpgrade; // Number of houses to build in Tool Age (total 8)
    static int housesBuiltAfterUpgrade;   // Number of houses built in Tool Age

    // New state variables (user request)
    static bool granaryBuilt; // New: Whether the granary has been built
    static bool marketBuilt;  // New: Whether the market has been built
    static bool recallVillagers; // Flag to indicate if villagers are being recalled
    static bool upgradeStarted;  // Flag to indicate if upgrade has started
    static int upgradeBuilderSN; // Dedicated builder during upgrade
    static std::queue<int> buildingQueue; // Building task queue
    static int housesBuiltDuringUpgrade;  // Number of houses built during upgrade

    UsrAI(){this->id=0;}
    ~UsrAI(){}

private:
    // Determines if a map cell is land
    bool isLand(int type);
    // Determines if a map cell is ocean
    bool isOcean(int type);
    // Determines if a map cell is of land type
    bool isMapCellLand(int x, int y, const tagInfo& info);
    // Determines if a cell is adjacent to land
    bool isCellAdjacentToLand(int cx, int cy, const tagInfo& info);
    // Counts adjacent land tiles (8 directions) for a given cell
    int countAdjacentLand(int cx, int cy, const tagInfo& info);
    // Determines if a position is reachable
    bool isPositionReachable(int x, int y, const tagInfo& info);
    // Determines if a new dock position is too close to existing docks
    bool isTooCloseToExistingDocks(int newDockX, int newDockY, const tagInfo& info);
    // Determines if a building position is valid
    bool isPositionValidForBuilding(int x, int y, int width, int height, int buildingType, const tagInfo& info);
    // Determines if a house building position is valid
    bool isPositionValidForHouse(int x, int y, const tagInfo& info);
    // Finds a coastal position near the Town Center
    bool findCoastalPositionNearCenter(int& x, int& y, const tagInfo& info, const std::set<std::pair<int, int>>& excludedPositions);
    // Finds a dock position near fish resources
    bool findDockPositionNearFish(int& x, int& y, const std::pair<int, int>& targetFishPos, const tagInfo& info, const std::set<std::pair<int, int>>& excludedPositions);
    // Determines if a dock is near fish resources
    bool isDockNearFish(const std::pair<int, int>& fishPos, const tagInfo& info);
    // Assigns tasks to villagers (with limits)
    void assignTasksToVillagersWithLimits(const tagInfo& info, bool reserveOneIdleForDock);
    // Processes game data (called per frame)
    void processData() override;
    // Gets game information
    tagInfo getInfo(){return tagUsrGame.getInfo();}
    // Adds instruction to the instruction queue
    int AddToIns(instruction ins) override
    {
        UsrIns.lock.lock();
        ins.id=UsrIns.g_id;
        UsrIns.g_id++;
        UsrIns.instructions.push(ins);
        UsrIns.lock.unlock();
        return ins.id;
    }

    // Clears instruction return results
    void clearInsRet() override{tagUsrGame.clearInsRet();}
    // Finds the nearest resource
    int findNearestResource(const tagFarmer& farmer, int resourceType, const tagInfo& info, const std::unordered_set<int>& excludedSNs);
    // Initializes the Town Center
    void initializeCenter(const tagInfo& info);
    // House building stage logic
    void buildHousesPhase(const tagInfo& info);
    // Finds nearby empty position (modified: added building size and type parameters)
    bool findNearbyPosition(int& x, int& y, const tagInfo& info, int width = 2, int height = 2, int buildingType = -1);
    // Population growth stage logic
    void populationGrowthPhase(const tagInfo& info);
    // Produces villagers
    void produceVillagers(const tagInfo& info);
    // Resource collection stage logic
    void collectResourcesPhase(const tagInfo& info);
    // Build required buildings stage logic
    void buildRequiredBuildingsPhase(const tagInfo& info);
    // Age upgrade stage logic
    void upgradeAgePhase(const tagInfo& info);
    // Fishing boat building stage logic
    void buildFishingBoatPhase(const tagInfo& info);
    // Post-Tool Age stage logic
    void afterUpgradePhase(const tagInfo& info);
    // Warship production stage logic
    void buildWarshipsPhase(const tagInfo& info);
    // Exploration stage logic
    void explorePhase(const tagInfo& info);
    // Initializes fish resource positions
    void initializeFishPositions(const tagInfo& info);
    // Assigns fishing boats to fish resources
    void assignFishingBoatsToFishResources(const tagInfo& info);
    // Finds the best stock position (near trees)
    bool findBestStockPosition(int& x, int& y, const tagInfo& info);
    // Forms warship fleets
    void formWarshipFleets(const tagInfo& info);
};

#endif


//UsrAI.cpp
//UsrAI.cpp
#include "UsrAI.h"
#include <iostream>
#include <algorithm>
#include <ctime>
#include <sstream>
#include <unordered_set>
#include <string>
#include <climits>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <queue>

#define ACTION_OK 0

using namespace std;

tagGame tagUsrGame;
ins UsrIns;
tagInfo UsrAI::prevInfo;
int UsrAI::center_x = 0;
int UsrAI::center_y = 0;
bool UsrAI::centerInitialized = false;
set<pair<int, int>> UsrAI::occupiedPositions;
int UsrAI::houseCount = 0;
int UsrAI::housesUnderConstruction = 0;
UsrAI::GameStage UsrAI::currentStage = UsrAI::STAGE_INITIAL;
int UsrAI::searchRadius = 1;
int UsrAI::lastHouseX = -1;
int UsrAI::lastHouseY = -1;
int UsrAI::houseBuilderSN = -1;


int UsrAI::targetPopulation = 0;
time_t UsrAI::lastVillagerProductionTime = time(nullptr);
bool UsrAI::buildingHousesInProgressInPopulationStage = false;


bool UsrAI::stockBuilt = false;
bool UsrAI::dockBuilt = false;
bool UsrAI::fishingBoatBuilt = false;
bool UsrAI::ageUpgraded = false;
int UsrAI::dockBuilderSN = -1;
bool UsrAI::dockBuilderReserved = false;
bool UsrAI::dockConstructionStarted = false;
int UsrAI::totalDocksPresent = 0;
int UsrAI::completedDocksCount = 0;

int UsrAI::fishingBoatCount = 0;
std::map<int, int> UsrAI::dockFishingBoatCount;

// Initialize new static variables for warship production
int UsrAI::warshipCount = 0;
std::map<int, int> UsrAI::dockWarshipCount;

// Initialize new static variables for warship fleets and targets
std::vector<std::vector<int>> UsrAI::warshipFleets;
std::map<int, std::pair<int, int>> UsrAI::fleetExplorationTargets;
std::map<int, int> UsrAI::fleetAttackTargetsSN;
std::unordered_set<int> UsrAI::assignedWarships;
bool UsrAI::fleetsFormed = false; // New: Whether warship fleets have been initially formed


int UsrAI::foundDockX = -1;
int UsrAI::foundDockY = -1;
bool UsrAI::dockPositionFound = false;


std::vector<std::pair<int, int>> UsrAI::fishPositions;
bool UsrAI::fishPositionsInitialized = false;
std::unordered_set<int> UsrAI::ordinaryVillagers;

// New static variables for STAGE_AFTER_UPGRADE
int UsrAI::villagersToProduceAfterUpgrade = 0;
int UsrAI::villagersProducedAfterUpgrade = 0;
int UsrAI::existingStocksAtUpgrade = 0;

const int MAX_HOUSE_SEARCH_RADIUS = 15;

// Initialize new dedicated builder variables
int UsrAI::toolAgeBuilderSN = -1;
bool UsrAI::toolAgeBuilderAssigned = false;
int UsrAI::housesToBuildAfterUpgrade = 4; // This will be set to 8 in upgradeAgePhase
int UsrAI::housesBuiltAfterUpgrade = 0;

// New: Granary and Market status initialization
bool UsrAI::granaryBuilt = false;
bool UsrAI::marketBuilt = false;

// User requested new static variables initialization
bool UsrAI::recallVillagers = false;
bool UsrAI::upgradeStarted = false;
int UsrAI::upgradeBuilderSN = -1;
std::queue<int> UsrAI::buildingQueue;
int UsrAI::housesBuiltDuringUpgrade = 0;

// ... Other code remains unchanged ...

// Checks if a map cell type is considered land (grass or shallows)
bool UsrAI::isLand(int type) {
    return type == MAPPATTERN_GRASS || type == MAPPATTERN_SHALLOWS;
}

// Checks if a map cell type is considered ocean
bool UsrAI::isOcean(int type) {
    return type == MAPPATTERN_OCEAN;
}

// Checks if a specific map cell is land
bool UsrAI::isMapCellLand(int x, int y, const tagInfo& info) {
    if (x < 0 || y < 0 || x >= 128 || y >= 128) {
        return false;
    }
    return this->isLand((*info.theMap)[x][y].type);
}

// Checks if a cell is adjacent to land (cardinal directions only)
bool UsrAI::isCellAdjacentToLand(int cx, int cy, const tagInfo& info) {
    // Only check 4 cardinal directions: Up, Down, Left, Right
    const int offsets[4][2] = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
    };
    for (const auto& offset : offsets) {
        int adjX = cx + offset[0];
        int adjY = cy + offset[1];
        if (adjX >= 0 && adjX < 128 && adjY >= 0 && adjY < 128) {
            if (this->isMapCellLand(adjX, adjY, info)) {
                return true;
            }
        }
    }
    return false;
}

// Counts adjacent land tiles (8 directions) for a given cell
int UsrAI::countAdjacentLand(int cx, int cy, const tagInfo& info) {
    int count = 0;
    const int offsets[8][2] = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}, // Cardinal
        {-1, -1}, {-1, 1}, {1, -1}, {1, 1} // Diagonal
    };

    for (const auto& offset : offsets) {
        int adjX = cx + offset[0];
        int adjY = cy + offset[1];
        if (adjX >= 0 && adjX < 128 && adjY >= 0 && adjY < 128) {
            if (this->isMapCellLand(adjX, adjY, info)) {
                count++;
            }
        }
    }
    return count;
}


// Checks if a position is reachable by a unit (adjacent to land)
bool UsrAI::isPositionReachable(int x, int y, const tagInfo& info) {
    const int offsets[8][2] = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1},
        {-1, -1}, {-1, 1}, {1, -1}, {1, 1}
    };

    for (const auto& offset : offsets) {
        int checkX = x + offset[0];
        int checkY = y + offset[1];

        if (checkX >= 0 && checkY >= 0 && checkX < 128 && checkY < 128) {
            if (this->isLand((*info.theMap)[checkX][checkY].type) &&
                !occupiedPositions.count({checkX, checkY})) {
                return true;
            }
        }
    }
    return false;
}

// Modified dock distance check logic
bool UsrAI::isTooCloseToExistingDocks(int newDockX, int newDockY, const tagInfo& info) {
    // Minimum edge-to-edge distance between docks is 4 blocks (a dock is 2x2)
    const int MIN_DOCK_SEPARATION_EDGE_TO_EDGE = 10;
    // Dock size is 2x2, so to ensure edge distance, add dock size itself
    const int DOCK_SIZE = 2;
    // Calculate maximum allowed coordinate difference for closeness
    const int MAX_COORD_DIFF_FOR_CLOSENESS = DOCK_SIZE + MIN_DOCK_SEPARATION_EDGE_TO_EDGE; // 2 + 4 = 6

    for (const auto& b : info.buildings) {
        // Only consider completed docks
        if (b.Type == BUILDING_DOCK && b.Percent == 100) {
            int existingDockX = b.BlockDR;
            int existingDockY = b.BlockUR;

            // Calculate absolute difference in top-left coordinates between new and existing docks
            int diffX = abs(newDockX - existingDockX);
            int diffY = abs(newDockY - existingDockY);

            // If the distance in X or Y direction is less than the minimum required distance, they are considered too close.
            if (diffX < MAX_COORD_DIFF_FOR_CLOSENESS && diffY < MAX_COORD_DIFF_FOR_CLOSENESS) {
                this->DebugText("  Candidate dock position (" + to_string(newDockX) + "," + to_string(newDockY) + ") is too close to existing dock (" + to_string(existingDockX) + "," + to_string(existingDockY) + "). X-diff: " + to_string(diffX) + ", Y-diff: " + to_string(diffY) + ", Min allowed diff: " + to_string(MAX_COORD_DIFF_FOR_CLOSENESS));
                return true;
            }
        }
    }
    return false;
}


// Initializes the Town Center and sets initial game stage
void UsrAI::initializeCenter(const tagInfo& info) {
    // Seed the random number generator only once at startup
    srand(time(NULL));

    for (const auto& building : info.buildings) {
        if (building.Type == BUILDING_CENTER) {
            center_x = building.BlockDR;
            center_y = building.BlockUR;
            centerInitialized = true;
            this->DebugText("Town Center located at (" + to_string(center_x) + "," + to_string(center_y) + ")");

            // Mark Town Center's 3x3 area as occupied
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    occupiedPositions.insert({center_x + i, center_y + j});
                }
            }

            currentStage = STAGE_BUILD_HOUSES;
            this->DebugText("=== Entering House Building Stage ===");

            // Attempt to find initial dock position near fish resources
            if (!dockPositionFound) {
                std::set<std::pair<int, int>> tempExcludedPositions; // Not used currently, but kept for consistency
                if (!fishPositionsInitialized) {
                    this->initializeFishPositions(info);
                }
                // Try to find a dock position near the closest fish resource
                if (!fishPositions.empty() && this->findDockPositionNearFish(foundDockX, foundDockY, fishPositions[0], info, tempExcludedPositions)) {
                    dockPositionFound = true;
                    this->DebugText("Initial dock position search successful: stored at (" + to_string(foundDockX) + "," + to_string(foundDockY) + ")");
                } else {
                    this->DebugText("Initial dock position search failed, will retry later");
                }
            }

            // Assign initial house builder and populate ordinary villagers
            if (!info.farmers.empty()) {
                houseBuilderSN = info.farmers[0].SN;
                this->DebugText("Assigned villager #" + to_string(houseBuilderSN) + " as house builder.");

                for (size_t i = 0; i < info.farmers.size(); i++) {
                    if (info.farmers[i].SN != houseBuilderSN) {
                        ordinaryVillagers.insert(info.farmers[i].SN);
                        this->DebugText("Villager #" + to_string(info.farmers[i].SN) + " added to ordinary villagers set.");
                    }
                }
            }
            break; // Town Center found, exit loop
        }
    }
}

// Determines if a given position is valid for building a structure of specified type and size
bool UsrAI::isPositionValidForBuilding(int x, int y, int width, int height, int buildingType, const tagInfo& info) {
    int firstHeight = -2; // Used to check consistent height for land buildings

    // Check bounds, existing buildings, and resources for the entire building area
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            int checkX = x + i;
            int checkY = y + j;

            if (checkX < 0 || checkY < 0 || checkX >= 128 || checkY >= 128) {
                this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") is out of map bounds.");
                return false;
            }

            // For non-dock buildings, check if the terrain is valid land and has consistent height
            if (buildingType != BUILDING_DOCK) {
                if (!this->isLand((*info.theMap)[checkX][checkY].type) || (*info.theMap)[checkX][checkY].height == -1) {
                    this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") is not valid land or slope for non-dock building.");
                    return false;
                }
                if (firstHeight == -2) {
                    firstHeight = (*info.theMap)[checkX][checkY].height;
                } else if ((*info.theMap)[checkX][checkY].height != firstHeight) {
                    this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") has inconsistent height for non-dock building.");
                    return false;
                }
            }

            // Check if the position is already occupied by a planned building
            if (occupiedPositions.count({checkX, checkY})) {
                this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") is already occupied by a planned building.");
                return false;
            }

            // Check for overlap with existing buildings
            for (const auto& b : info.buildings) {
                int b_width, b_height;
                // Determine building dimensions based on type
                if (b.Type == BUILDING_DOCK) { b_width = 2; b_height = 2; }
                else if (b.Type == BUILDING_STOCK || b.Type == BUILDING_CENTER || b.Type == BUILDING_GRANARY || b.Type == BUILDING_ARMYCAMP || b.Type == BUILDING_MARKET || b.Type == BUILDING_FARM || b.Type == BUILDING_RANGE || b.Type == BUILDING_STABLE) { b_width = 3; b_height = 3; }
                else if (b.Type == BUILDING_HOME || b.Type == BUILDING_ARROWTOWER) { b_width = 2; b_height = 2; }
                else { b_width = 1; b_height = 1; } // Default for unknown types

                if (checkX >= b.BlockDR && checkX < (b.BlockDR + b_width) &&
                    checkY >= b.BlockUR && checkY < (b.BlockUR + b_height)) {
                    this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") overlaps with existing building SN " + to_string(b.SN) + " Type " + to_string(b.Type) + " at (" + to_string(b.BlockDR) + "," + to_string(b.BlockUR) + ").");
                    return false;
                }
            }

            // Check for overlap with resources
            for (const auto& res : info.resources) {
                if (res.BlockDR == checkX && res.BlockUR == checkY) {
                    this->DebugText("  Position (" + to_string(checkX) + "," + to_string(checkY) + ") overlaps with resource SN " + to_string(res.SN) + " Type " + to_string(res.Type) + ".");
                    return false;
                }
            }
        }
    }

    // Specific validation for DOCK buildings
    if (buildingType == BUILDING_DOCK) {
        // Ensure dock is 2x2
        if (width != 2 || height != 2) {
            this->DebugText("  Dock must be 2x2, but requested width/height is " + to_string(width) + "x" + to_string(height) + ".");
            return false;
        }

        // 1. Ensure the entire 2x2 area for the dock is ocean
        if (!(this->isOcean((*info.theMap)[x][y].type) &&
              this->isOcean((*info.theMap)[x + 1][y].type) &&
              this->isOcean((*info.theMap)[x][y + 1].type) &&
              this->isOcean((*info.theMap)[x + 1][y + 1].type))) {
            this->DebugText("  2x2 area for dock at (" + to_string(x) + "," + to_string(y) + ") is not all ocean.");
            return false;
        }

        // 2. MODIFIED: Ensure at least one full side of the 2x2 dock area is adjacent to land.
        // This ensures a proper "on-shore" placement.
        bool hasFullSideAdjacentToLand = false;

        // Check left side: (x-1, y) and (x-1, y+1)
        if (x - 1 >= 0 &&
            this->isMapCellLand(x - 1, y, info) &&
            this->isMapCellLand(x - 1, y + 1, info)) {
            hasFullSideAdjacentToLand = true;
            this->DebugText("  Dock at (" + to_string(x) + "," + to_string(y) + ") has full left side adjacent to land.");
        }
        // Check right side: (x+2, y) and (x+2, y+1)
        if (!hasFullSideAdjacentToLand && x + 2 < 128 &&
            this->isMapCellLand(x + 2, y, info) &&
            this->isMapCellLand(x + 2, y + 1, info)) {
            hasFullSideAdjacentToLand = true;
            this->DebugText("  Dock at (" + to_string(x) + "," + to_string(y) + ") has full right side adjacent to land.");
        }
        // Check top side: (x, y-1) and (x+1, y-1)
        if (!hasFullSideAdjacentToLand && y - 1 >= 0 &&
            this->isMapCellLand(x, y - 1, info) &&
            this->isMapCellLand(x + 1, y - 1, info)) {
            hasFullSideAdjacentToLand = true;
            this->DebugText("  Dock at (" + to_string(x) + "," + to_string(y) + ") has full top side adjacent to land.");
        }
        // Check bottom side: (x, y+2) and (x+1, y+2)
        if (!hasFullSideAdjacentToLand && y + 2 < 128 &&
            this->isMapCellLand(x, y + 2, info) &&
            this->isMapCellLand(x + 1, y + 2, info)) {
            hasFullSideAdjacentToLand = true;
            this->DebugText("  Dock at (" + to_string(x) + "," + to_string(y) + ") has full bottom side adjacent to land.");
        }

        if (!hasFullSideAdjacentToLand) {
            this->DebugText("Dock position (" + to_string(x) + "," + to_string(y) + ") does not have any full side adjacent to land.");
            return false; // No full side adjacent to land
        }
    }

    return true; // Position is valid for building
}

// Determines if a house building position is valid
bool UsrAI::isPositionValidForHouse(int x, int y, const tagInfo& info) {
    return this->isPositionValidForBuilding(x, y, 2, 2, BUILDING_HOME, info);
}

// Finds a coastal position near the Town Center for dock building
bool UsrAI::findCoastalPositionNearCenter(int& x, int& y, const tagInfo& info, const std::set<std::pair<int, int>>& excludedPositions) {
    this->DebugText("Searching for coastal position near Town Center...");
    const int MAX_RADIUS = 8; // Search radius around Town Center

    for (int r = 1; r <= MAX_RADIUS; r++) { // Iterate through increasing radii
        for (int i = -r; i <= r; ++i) {
            for (int j = -r; j <= r; ++j) {
                // Only check cells on the perimeter of the square search radius
                if (abs(i) != r && abs(j) != r) continue;

                int checkX = center_x + i;
                int checkY = center_y + j;

                // Check map bounds
                if (checkX < 0 || checkY < 0 || checkX >= 128 || checkY >= 128) {
                    continue;
                }

                // Skip excluded positions (e.g., previously failed attempts)
                if (excludedPositions.count({checkX, checkY})) {
                    continue;
                }

                // Check if the position is valid for building a dock (2x2)
                if (this->isPositionValidForBuilding(checkX, checkY, 2, 2, BUILDING_DOCK, info)) {
                    // Check if the position is reachable by villagers (adjacent to land)
                    if (this->isPositionReachable(checkX, checkY, info)) {
                        this->DebugText("Found dock position near Town Center: (" + to_string(checkX) + "," + to_string(checkY) + ")");
                        x = checkX;
                        y = checkY;
                        return true;
                    } else {
                        this->DebugText("Dock position near Town Center (" + to_string(checkX) + "," + to_string(checkY) + ") is valid but unreachable by villagers.");
                    }
                }
            }
        }
    }

    this->DebugText("No suitable dock position found near Town Center.");
    return false;
}


// Initializes the list of fish resource positions, sorted by distance from Town Center
void UsrAI::initializeFishPositions(const tagInfo& info) {
    for (const auto& res : info.resources) {
        if (res.Type == RESOURCE_FISH) {
            fishPositions.push_back({res.BlockDR, res.BlockUR});
            this->DebugText("Found fish resource at: (" + to_string(res.BlockDR) + "," + to_string(res.BlockUR) + ")");
        }
    }
    // Sort fish positions by distance from Town Center (closest first)
    std::sort(fishPositions.begin(), fishPositions.end(), [&](const std::pair<int, int>& a, const std::pair<int, int>& b) {
        int distA = abs(a.first - center_x) + abs(a.second - center_y);
        int distB = abs(b.first - center_x) + abs(b.second - center_y);
        return distB < distA; // Sort in ascending order of distance
    });
    this->DebugText("Fish resource positions sorted by distance from Town Center.");
    fishPositionsInitialized = true;
}

// Checks if an existing dock is near a given fish resource
bool UsrAI::isDockNearFish(const std::pair<int, int>& fishPos, const tagInfo& info) {
    const int DOCK_NEAR_FISH_RADIUS = 5; // Radius to consider a dock "near" fish
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_DOCK) {
            int minDist = INT_MAX;
            // Check distance from each of the dock's 2x2 cells to the fish position
            for (int i = 0; i < 2; ++i) {
                for (int j = 0; j < 2; ++j) {
                    int dockCornerX = b.BlockDR + i;
                    int dockCornerY = b.BlockUR + j;
                    int dist = abs(dockCornerX - fishPos.first) + abs(dockCornerY - fishPos.second);
                    if (dist < minDist) {
                        minDist = dist;
                    }
                }
            }
            if (minDist <= DOCK_NEAR_FISH_RADIUS) {
                this->DebugText("Dock SN " + to_string(b.SN) + " at (" + to_string(b.BlockDR) + "," + to_string(b.BlockUR) + ") is near fish at (" + to_string(fishPos.first) + "," + to_string(fishPos.second) + "). Distance: " + to_string(minDist));
                return true;
            }
        }
    }
    return false;
}

// Finds a valid dock position near a specific fish resource
bool UsrAI::findDockPositionNearFish(int& x, int& y, const std::pair<int, int>& targetFishPos, const tagInfo& info, const std::set<std::pair<int, int>>& excludedPositions) {
    this->DebugText("Starting search for dock position near specific fish resource: (" + to_string(targetFishPos.first) + "," + to_string(targetFishPos.second) + ")");

    const int SEARCH_RADIUS_AROUND_FISH_FOR_DOCK = 8; // Increased search radius for dock positions around fish

    int fishX = targetFishPos.first;
    int fishY = targetFishPos.second;

    int bestDockX = -1, bestDockY = -1;
    double maxConnectionScore = -1.0; // Use double for score to allow more nuanced weighting

    // Iterate through potential dock positions around the fish resource
    // A dock is 2x2. We want to find its top-left corner (dockCandidateX, dockCandidateY)
    for (int dx_dock = -SEARCH_RADIUS_AROUND_FISH_FOR_DOCK; dx_dock <= SEARCH_RADIUS_AROUND_FISH_FOR_DOCK; ++dx_dock) {
        for (int dy_dock = -SEARCH_RADIUS_AROUND_FISH_FOR_DOCK; dy_dock <= SEARCH_RADIUS_AROUND_FISH_FOR_DOCK; ++dy_dock) {
            int dockCandidateX = fishX + dx_dock;
            int dockCandidateY = fishY + dy_dock;

            // Skip excluded positions
            if (excludedPositions.count({dockCandidateX, dockCandidateY})) {
                continue;
            }

            // Check if the candidate dock position is too close to existing docks
            if (this->isTooCloseToExistingDocks(dockCandidateX, dockCandidateY, info)) {
                continue;
            }

            // Validate the dock position using isPositionValidForBuilding (ensures it's in ocean and adjacent to land)
            if (this->isPositionValidForBuilding(dockCandidateX, dockCandidateY, 2, 2, BUILDING_DOCK, info)) {
                // Ensure the dock is reachable by villagers
                if (this->isPositionReachable(dockCandidateX, dockCandidateY, info)) {
                    // Calculate a connection score for this valid dock position
                    double currentConnectionScore = 0.0;
                    int numFullSidesAdjacent = 0;

                    // Check and score for each full side adjacent to land
                    // Left side: (dockCandidateX-1, dockCandidateY) and (dockCandidateX-1, dockCandidateY+1)
                    if (dockCandidateX - 1 >= 0 &&
                        this->isMapCellLand(dockCandidateX - 1, dockCandidateY, info) &&
                        this->isMapCellLand(dockCandidateX - 1, dockCandidateY + 1, info)) {
                        numFullSidesAdjacent++;
                        currentConnectionScore += 100.0; // High score for a full side
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX - 1, dockCandidateY, info);
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX - 1, dockCandidateY + 1, info);
                    }
                    // Right side: (dockCandidateX+2, dockCandidateY) and (dockCandidateX+2, dockCandidateY+1)
                    if (dockCandidateX + 2 < 128 &&
                        this->isMapCellLand(dockCandidateX + 2, dockCandidateY, info) &&
                        this->isMapCellLand(dockCandidateX + 2, dockCandidateY + 1, info)) {
                        numFullSidesAdjacent++;
                        currentConnectionScore += 100.0;
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX + 2, dockCandidateY, info);
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX + 2, dockCandidateY + 1, info);
                    }
                    // Top side: (dockCandidateX, dockCandidateY-1) and (dockCandidateX+1, dockCandidateY-1)
                    if (dockCandidateY - 1 >= 0 &&
                        this->isMapCellLand(dockCandidateX, dockCandidateY - 1, info) &&
                        this->isMapCellLand(dockCandidateX + 1, dockCandidateY - 1, info)) {
                        numFullSidesAdjacent++;
                        currentConnectionScore += 100.0;
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX, dockCandidateY - 1, info);
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX + 1, dockCandidateY - 1, info);
                    }
                    // Bottom side: (dockCandidateX, dockCandidateY+2) and (dockCandidateX+1, dockCandidateY+2)
                    if (dockCandidateY + 2 < 128 &&
                        this->isMapCellLand(dockCandidateX, dockCandidateY + 2, info) &&
                        this->isMapCellLand(dockCandidateX + 1, dockCandidateY + 2, info)) {
                        numFullSidesAdjacent++;
                        currentConnectionScore += 100.0;
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX, dockCandidateY + 2, info);
                        currentConnectionScore += this->countAdjacentLand(dockCandidateX + 1, dockCandidateY + 2, info);
                    }

                    // Prioritize positions with more full sides adjacent to land
                    currentConnectionScore += numFullSidesAdjacent * 500.0; // Even higher bonus for more sides

                    this->DebugText("  Valid dock candidate: (" + to_string(dockCandidateX) + "," + to_string(dockCandidateY) + ") Score: " + to_string(currentConnectionScore));

                    if (currentConnectionScore > maxConnectionScore) {
                        maxConnectionScore = currentConnectionScore;
                        bestDockX = dockCandidateX;
                        bestDockY = dockCandidateY;
                    }
                } else {
                    this->DebugText("Dock position near fish (" + to_string(dockCandidateX) + "," + to_string(dockCandidateY) + ") is valid but unreachable by villagers.");
                }
            }
        }
    }

    if (bestDockX != -1) {
        x = bestDockX;
        y = bestDockY;
        this->DebugText("Found best dock position: (" + to_string(x) + "," + to_string(y) + ") with max score: " + to_string(maxConnectionScore));
        return true;
    }

    this->DebugText("No suitable dock position found near specific fish resource: (" + to_string(targetFishPos.first) + "," + to_string(targetFishPos.second) + ") after exhaustive search.");
    return false;
}



// Assigns tasks to ordinary villagers, with limits on food/wood workers and a reservation for dock builder
void UsrAI::assignTasksToVillagersWithLimits(const tagInfo& info, bool reserveOneIdleForDock) {
    // Remove dead villagers from the ordinaryVillagers set
    for (auto it = ordinaryVillagers.begin(); it != ordinaryVillagers.end(); ) {
        bool exists = false;
        for (const auto& farmer : info.farmers) {
            if (farmer.SN == *it) {
                exists = true;
                break;
            }
        }
        if (!exists) {
            this->DebugText("Removing dead villager #" + to_string(*it) + " from ordinary villagers set.");
            it = ordinaryVillagers.erase(it);
        }
        else {
            ++it;
        }
    }

    // Add newly produced or unassigned farmers to the ordinaryVillagers set
    for (const auto& farmer : info.farmers) {
        if (farmer.FarmerSort != 0) continue; // Only consider land villagers
        // Exclude specific builders (house, dock, tool age, upgrade) from general assignment pool
        if ((farmer.SN == houseBuilderSN && !dockBuilderReserved && currentStage == STAGE_BUILD_HOUSES) || (farmer.SN == dockBuilderSN && dockBuilderReserved)) {
            continue;
        }
        if (currentStage == STAGE_AFTER_UPGRADE && toolAgeBuilderAssigned && farmer.SN == toolAgeBuilderSN) {
            continue;
        }
        if (upgradeStarted && farmer.SN == upgradeBuilderSN) {
            continue;
        }

        // Add to ordinary villagers if not already present
        if (ordinaryVillagers.find(farmer.SN) == ordinaryVillagers.end()) {
            ordinaryVillagers.insert(farmer.SN);
            this->DebugText("New villager #" + to_string(farmer.SN) + " added to ordinary villagers set.");
        }
    }

    // Count current workers by type
    int woodWorkers = 0;
    int foodWorkers = 0;
    int buildWorkers = 0;
    int idleCount = 0;

    for (const auto& farmer : info.farmers) {
        // Exclude dedicated builders from general task statistics
        if (currentStage == STAGE_AFTER_UPGRADE && toolAgeBuilderAssigned && farmer.SN == toolAgeBuilderSN) {
            continue;
        }
        if (upgradeStarted && farmer.SN == upgradeBuilderSN) {
            continue;
        }
        // Only count ordinary villagers
        if (ordinaryVillagers.count(farmer.SN) == 0) {
            continue;
        }

        if (farmer.NowState == HUMAN_STATE_IDLE) {
            idleCount++;
        } else if (farmer.NowState == HUMAN_STATE_WORKING) {
            for (const auto& res : info.resources) {
                if (res.SN == farmer.WorkObjectSN) {
                    if (res.Type == RESOURCE_TREE) {
                        woodWorkers++;
                    } else if (res.Type == RESOURCE_GAZELLE ||
                               res.Type == RESOURCE_ELEPHANT ||
                               res.Type == RESOURCE_FISH) {
                        foodWorkers++;
                    }
                    break;
                }
            }
        } else if (farmer.NowState == HUMAN_STATE_WALKING) {
            // Check if walking to a building site
            bool isBuildingTarget = false;
            for (const auto& b : info.buildings) {
                if (b.Percent < 100 && // Building is under construction
                    (int)(farmer.DR0 / BLOCKSIDELENGTH) >= b.BlockDR &&
                    (int)(farmer.DR0 / BLOCKSIDELENGTH) < (b.BlockDR + (b.Type == BUILDING_DOCK ? 2 : (b.Type == BUILDING_STOCK ? 3 : 2))) && // Adjusted for dock/stock size
                    (int)(farmer.UR0 / BLOCKSIDELENGTH) >= b.BlockUR &&
                    (int)(farmer.UR0 / BLOCKSIDELENGTH) < (b.BlockUR + (b.Type == BUILDING_DOCK ? 2 : (b.Type == BUILDING_STOCK ? 3 : 2)))) {
                    isBuildingTarget = true;
                    break;
                }
            }
            if (isBuildingTarget) {
                buildWorkers++;
            }
        }
    }

    this->DebugText("Ordinary Villager Task Stats: Idle=" + to_string(idleCount) +
              " Wood=" + to_string(woodWorkers) +
              " Food=" + to_string(foodWorkers) +
              " Build=" + to_string(buildWorkers));

    // Collect available idle ordinary farmers, sorted by distance to Town Center
    std::vector<const tagFarmer*> availableIdleFarmers;
    for (const auto& farmer : info.farmers) {
        // Exclude dedicated builders from available idle villagers for general tasks
        if (currentStage == STAGE_AFTER_UPGRADE && toolAgeBuilderAssigned && farmer.SN == toolAgeBuilderSN) {
            continue;
        }
        if (upgradeStarted && farmer.SN == upgradeBuilderSN) {
            continue;
        }

        if (ordinaryVillagers.count(farmer.SN) && farmer.NowState == HUMAN_STATE_IDLE) {
            availableIdleFarmers.push_back(&farmer);
        }
    }

    std::sort(availableIdleFarmers.begin(), availableIdleFarmers.end(), [&](const tagFarmer* a, const tagFarmer* b) {
        int distA = abs(a->BlockDR - center_x) + abs(a->BlockUR - center_y);
        int distB = abs(b->BlockDR - center_x) + abs(b->BlockUR - center_y);
        return distB < distA; // Sort by distance, farther first
    });

    // Assign tasks to idle farmers
    for (const tagFarmer* farmer_ptr : availableIdleFarmers) {
        const tagFarmer& current_farmer = *farmer_ptr;
        bool assignedThisTurn = false;
        std::unordered_set<int> villagerExcludedResources; // Resources to exclude for this specific villager

        // Prioritize food collection if not in Tool Age and food workers are below limit
        if (currentStage != STAGE_AFTER_UPGRADE &&
            !upgradeStarted && // Also exclude if upgrade has started
            foodWorkers < 3) // Target 3 food workers
        {
            int targetFoodSN = -1;
            while (!assignedThisTurn) {
                // Try gazelle, then elephant, then fish
                targetFoodSN = this->findNearestResource(current_farmer, RESOURCE_GAZELLE, info, villagerExcludedResources);
                if (targetFoodSN == -1) targetFoodSN = this->findNearestResource(current_farmer, RESOURCE_ELEPHANT, info, villagerExcludedResources);
                if (targetFoodSN == -1) targetFoodSN = this->findNearestResource(current_farmer, RESOURCE_FISH, info, villagerExcludedResources);

                if (targetFoodSN != -1) {
                    int ret = HumanAction(farmer_ptr->SN, targetFoodSN);
                    if (ret > 0) {
                        this->DebugText("Villager #" + to_string(farmer_ptr->SN) + " assigned to collect food.");
                        foodWorkers++;
                        assignedThisTurn = true;
                    } else {
                        villagerExcludedResources.insert(targetFoodSN); // Exclude if unreachable
                        this->DebugText("Villager #" + to_string(farmer_ptr->SN) + " cannot reach food resource SN " + to_string(targetFoodSN) + ". Trying other food resources.");
                    }
                } else {
                    break; // No more food resources found
                }
            }
        }

        if (assignedThisTurn) continue; // If assigned food, move to next villager

        // Assign wood collection if not already assigned
        int targetTreeSN = -1;
        while (!assignedThisTurn) {
            targetTreeSN = this->findNearestResource(current_farmer, RESOURCE_TREE, info, villagerExcludedResources);
            if (targetTreeSN != -1) {
                int ret = HumanAction(farmer_ptr->SN, targetTreeSN);
                if (ret > 0) {
                    this->DebugText("Villager #" + to_string(farmer_ptr->SN) + " assigned to chop wood.");
                    woodWorkers++;
                    assignedThisTurn = true;
                } else {
                    villagerExcludedResources.insert(targetTreeSN); // Exclude if unreachable
                    this->DebugText("Villager #" + to_string(farmer_ptr->SN) + " cannot reach wood resource SN " + to_string(targetTreeSN) + ". Trying other wood resources.");
                }
            } else {
                // If no trees found, villager will remain idle.
                this->DebugText("Villager #" + to_string(farmer_ptr->SN) + " found no trees to chop, will remain idle.");
                break;
            }
        }
    }
}


// Resource collection stage logic
void UsrAI::collectResourcesPhase(const tagInfo& info) {
    this->DebugText("Resource Collection Phase | Wood: " + to_string(info.Wood) +
              " | Food: " + to_string(info.Meat) +
              " | Villagers: " + to_string(info.farmers.size()));

    int currentStockCount = 0;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_STOCK && b.Percent == 100) {
            currentStockCount++;
        }
    }
    this->DebugText("Stocks: " + to_string(currentStockCount));

    // Initialize fish positions if not already done
    if (!fishPositionsInitialized) {
        this->initializeFishPositions(info);
    }

    // Assign tasks to villagers
    this->assignTasksToVillagersWithLimits(info, !dockBuilt); // Reserve one idle villager for dock if not built
}


// Population growth stage logic
void UsrAI::populationGrowthPhase(const tagInfo& info) {
    int currentPopulation = info.farmers.size() + info.armies.size();
    int populationCapacity = info.Human_MaxNum;

    string status = "Population Growth Phase | ";
    status += "Current: " + to_string(currentPopulation) + "/" + to_string(populationCapacity);
    status += " | Target: " + to_string(targetPopulation);
    this->DebugText(status);

    this->DebugText("Population Growth Phase: Attempting to produce villagers.");
    this->produceVillagers(info); // Attempt to produce villagers

    // Transition condition: population target reached AND all initial houses built
    if (currentPopulation >= targetPopulation && houseCount == TARGET_HOUSES && housesUnderConstruction == 0) {
        this->DebugText("=== Population target reached and all houses built, entering Required Buildings Stage ===");
        currentStage = STAGE_BUILD_REQUIRED_BUILDINGS;

        // If house builder is still assigned and dock builder is not, reassign house builder as dock builder
        if (houseBuilderSN != -1 && dockBuilderSN == -1) {
            dockBuilderSN = houseBuilderSN;
            dockBuilderReserved = true;
            this->DebugText("Assigned villager #" + to_string(dockBuilderSN) + " as dock builder (after all houses built).");
            // Remove from ordinary villagers set if it was there
            if (ordinaryVillagers.count(dockBuilderSN)) {
                ordinaryVillagers.erase(dockBuilderSN);
                this->DebugText("Removed dock builder #" + to_string(dockBuilderSN) + " from ordinary villagers set.");
            }
        }
        return; // Stage changed, exit
    }

    // Assign tasks to villagers if not transitioning
    this->assignTasksToVillagersWithLimits(info, !dockBuilt); // Reserve one idle villager for dock if not built
}

// Builds required buildings (docks and stocks)
void UsrAI::buildRequiredBuildingsPhase(const tagInfo& info) {
    this->DebugText("Required Buildings Phase | Stock: " + string(stockBuilt ? "Completed" : "Pending") +
              " | Current Docks Total: " + to_string(totalDocksPresent) +
              " | Completed Docks: " + to_string(completedDocksCount) +
              " | Target Docks: " + to_string(TARGET_DOCKS_NUM));

    int docksUnderConstruction = 0;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_DOCK && b.Percent < 100) {
            docksUnderConstruction++;
        }
    }
    this->DebugText("Docks Under Construction: " + to_string(docksUnderConstruction));

    // Transition condition: all target docks are completed
    if (completedDocksCount >= TARGET_DOCKS_NUM) {
        currentStage = STAGE_BUILD_FISHING_BOAT;
        this->DebugText("=== All target docks built, entering Fishing Boat Production Stage ===");
        // Release dock builder back to ordinary villagers if assigned
        if (dockBuilderSN != -1 && ordinaryVillagers.find(dockBuilderSN) == ordinaryVillagers.end()) {
            ordinaryVillagers.insert(dockBuilderSN);
            dockBuilderReserved = false;
            this->DebugText("Dock builder #" + to_string(dockBuilderSN) + " released and added to ordinary villagers set.");
        }
        return; // Stage changed, exit
    }

    this->DebugText("buildRequiredBuildingsPhase: Evaluating dock construction. Dock built: " + to_string(dockBuilt) +
              ", Dock construction started: " + to_string(dockConstructionStarted) +
              ", Dock builder reserved: " + to_string(dockBuilderReserved) +
              ", Wood: " + to_string(info.Wood) + ", Needed: " + to_string(BUILD_DOCK_WOOD));

    // Logic for building docks
    if (completedDocksCount < TARGET_DOCKS_NUM && docksUnderConstruction == 0) {
        tagFarmer* builderFarmer = nullptr;

        // Try to find the designated dock builder
        if (dockBuilderSN != -1) {
            for (const auto& farmer : info.farmers) {
                if (farmer.SN == dockBuilderSN && farmer.FarmerSort == 0) { // Ensure it's a land villager
                    builderFarmer = const_cast<tagFarmer*>(&farmer);
                    this->DebugText("buildRequiredBuildingsPhase: Found designated dock builder villager #" + to_string(builderFarmer->SN));
                    break;
                }
            }
        }

        // If designated builder not found or busy, try to reassign an idle villager
        if (builderFarmer == nullptr && dockBuilderSN != -1) {
            bool isBuilderBusy = false;
            for (const auto& farmer : info.farmers) {
                if (farmer.SN == dockBuilderSN &&
                    farmer.NowState != HUMAN_STATE_IDLE) {
                    isBuilderBusy = true;
                    break;
                }
                if (farmer.SN == dockBuilderSN && farmer.NowState == HUMAN_STATE_IDLE) {
                    this->DebugText("Designated dock builder #" + to_string(dockBuilderSN) + " is idle but not selected. Resetting.");
                    dockBuilderSN = -1;
                    dockBuilderReserved = false;
                    break;
                }
            }

            if (!isBuilderBusy && dockBuilderSN != -1) {
                 this->DebugText("Designated dock builder #" + to_string(dockBuilderSN) + " not found or dead. Resetting.");
                 dockBuilderSN = -1;
                 dockBuilderReserved = false;
            } else if (isBuilderBusy) {
                this->DebugText("Designated dock builder #" + to_string(dockBuilderSN) + " is still busy. Waiting for idle.");
            }
        }

        // If no designated builder or it was reset, find a new idle villager
        if (builderFarmer == nullptr && dockBuilderSN == -1) {
             for (const auto& farmer : info.farmers) {
                if (farmer.NowState == HUMAN_STATE_IDLE && farmer.FarmerSort == 0) {
                    // Avoid using the house builder if it's reserved for houses (though at this stage, houses should be done)
                    if (farmer.SN == houseBuilderSN && !dockBuilderReserved) {
                        continue;
                    }
                    builderFarmer = const_cast<tagFarmer*>(&farmer);
                    dockBuilderSN = farmer.SN;
                    dockBuilderReserved = true;
                    ordinaryVillagers.erase(dockBuilderSN); // Remove from ordinary villagers set
                    this->DebugText("buildRequiredBuildingsPhase: Reassigned villager #" + to_string(builderFarmer->SN) + " as dock builder.");
                    break;
                }
            }
        }

        // If a builder is available, attempt to build a dock
        if (builderFarmer != nullptr) {
            int dockX = -1, dockY = -1;
            std::set<std::pair<int, int>> failedDockAttemptsThisCall; // To avoid retrying invalid positions in the same frame
            bool positionFound = false;
            bool shouldBreakLoop = false;

            // Iterate through fish positions to find a suitable dock location nearby
            for (const auto& fishPos : fishPositions) {
                // Skip if a dock is already near this fish resource
                if (this->isDockNearFish(fishPos, info)) {
                    this->DebugText("Skipping fish position (" + to_string(fishPos.first) + "," + to_string(fishPos.second) + ") as a dock already exists nearby.");
                    continue;
                }

                // Find a valid dock position near the current fish resource
                positionFound = this->findDockPositionNearFish(dockX, dockY, fishPos, info, failedDockAttemptsThisCall);
                if (positionFound) {
                    this->DebugText("Found new dock position near fish: (" + to_string(dockX) + "," + to_string(dockY) + ")");
                    if (info.Wood >= BUILD_DOCK_WOOD) { // Check for sufficient wood
                        this->DebugText("buildRequiredBuildingsPhase: Found dock build location (" + to_string(dockX) + "," + to_string(dockY) + "), attempting to build.");
                        int ret = HumanBuild(builderFarmer->SN, BUILDING_DOCK, dockX, dockY);
                        if (ret > 0) {
                            this->DebugText("Villager #" + to_string(builderFarmer->SN) + " dock build command successfully issued.");
                            dockConstructionStarted = true;
                            // Mark the 2x2 dock area as occupied
                            for (int i = 0; i < 2; i++) {
                                for (int j = 0; j < 2; j++) {
                                    occupiedPositions.insert({dockX+i, dockY+j});
                                }
                            }
                            return; // Command issued, exit function for this frame
                        } else {
                            this->DebugText("Villager #" + to_string(builderFarmer->SN) + " dock build command failed, error code: " + to_string(ret));
                            if (ret == ACTION_INVALID_HUMANBUILD_OVERLAP || ret == ACTION_INVALID_POSITION_NOT_FIT) {
                                failedDockAttemptsThisCall.insert({dockX, dockY}); // Add to exclusion list for this frame
                                this->DebugText("Position (" + to_string(dockX) + "," + to_string(dockY) + ") added to exclusion list, trying new position.");
                            } else {
                                this->DebugText("Non-position related error, cannot resolve this frame.");
                                shouldBreakLoop = true; // Break loop if error is not position-related
                                break;
                            }
                        }
                    } else {
                        this->DebugText("Not enough wood, need " + to_string(BUILD_DOCK_WOOD) + " wood to build dock.");
                        shouldBreakLoop = true; // Break loop if not enough resources
                        break;
                    }
                }
                if (shouldBreakLoop) break;
            }

            if (!positionFound && !shouldBreakLoop) {
                this->DebugText("buildRequiredBuildingsPhase: No suitable dock build location found near any fish resource.");
            }
        } else {
            this->DebugText("buildRequiredBuildingsPhase: No idle villager available for dock construction (or designated villager is busy).");
        }
    }

    this->DebugText("buildRequiredBuildingsPhase: Evaluating stock construction. Stock built: " + to_string(stockBuilt) +
              " | Completed Docks: " + to_string(completedDocksCount) +
              " | Target Docks: " + to_string(TARGET_DOCKS_NUM) +
              " | Wood: " + to_string(info.Wood) + ", Needed: " + to_string(BUILD_STOCK_WOOD));

    // Logic for building stocks (only after target docks are completed)
    if (!stockBuilt && completedDocksCount >= TARGET_DOCKS_NUM) {
        int buildX, buildY;
        // Find the best stock position near trees (Stock is 3x3)
        if (this->findBestStockPosition(buildX, buildY, info)) {
            if (info.Wood >= BUILD_STOCK_WOOD) { // Check for sufficient wood
                tagFarmer* builderForStock = nullptr;
                // Find an idle ordinary villager to build the stock
                for (const auto& farmer : info.farmers) {
                    if (ordinaryVillagers.count(farmer.SN) && farmer.NowState == HUMAN_STATE_IDLE && farmer.FarmerSort == 0) {
                        builderForStock = const_cast<tagFarmer*>(&farmer);
                        break;
                    }
                }

                if (builderForStock != nullptr) {
                    this->DebugText("buildRequiredBuildingsPhase: Found idle ordinary villager #" + to_string(builderForStock->SN) + " attempting to build stock.");
                    int ret = HumanBuild(builderForStock->SN, BUILDING_STOCK, buildX, buildY);
                    if (ret > 0) {
                        this->DebugText("Villager #" + to_string(builderForStock->SN) + " is building stock at: (" +
                                  to_string(buildX) + "," + to_string(buildY) + ")");
                        // Mark the 3x3 stock area as occupied
                        for (int i = 0; i < 3; i++) {
                            for (int j = 0; j < 3; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                    } else {
                        this->DebugText("Villager #" + to_string(builderForStock->SN) + " stock build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("No idle ordinary villager available for stock construction.");
                }
            } else {
                this->DebugText("Not enough wood, need " + to_string(BUILD_STOCK_WOOD) + " wood to build stock.");
            }
        }
    }
    this->assignTasksToVillagersWithLimits(info, false); // Assign tasks, no special dock builder reservation needed now
}

// Age upgrade stage logic
void UsrAI::upgradeAgePhase(const tagInfo& info) {
    this->DebugText("--- Entering Age Upgrade Stage ---");
    this->DebugText("Current Civilization Stage: " + to_string(info.civilizationStage));

    // Transition condition: Age has been upgraded to Tool Age
    if (info.civilizationStage == CIVILIZATION_TOOLAGE) {
        ageUpgraded = true;
        currentStage = STAGE_AFTER_UPGRADE; // Transition to new post-Tool Age stage
        villagersToProduceAfterUpgrade = 6;  // Set target for new villagers
        villagersProducedAfterUpgrade = 0;

        // Record existing stock count at upgrade time
        existingStocksAtUpgrade = 0;
        for (const auto& b : info.buildings) {
            if (b.Type == BUILDING_STOCK) {
                existingStocksAtUpgrade++;
            }
        }
        // Set housesToBuildAfterUpgrade to TARGET_HOUSES + 4 (4 initial + 4 extra)
        housesToBuildAfterUpgrade = TARGET_HOUSES + 4;
        this->DebugText("=== Age upgrade completed, entering Post-Tool Age Stage. Need to produce 6 villagers and ensure a total of " + to_string(TARGET_TOTAL_STOCKS) + " stocks, and a total of " + to_string(housesToBuildAfterUpgrade) + " houses ===");
        return; // Stage changed, exit
    }

    this->DebugText("Age Upgrade Stage | Need 500 food. Current Food: " + to_string(info.Meat));

    // Attempt to upgrade age if enough food
    if (info.Meat >= 500) {
        bool townCenterFound = false;
        for (const auto& building : info.buildings) {
            if (building.Type == BUILDING_CENTER) {
                townCenterFound = true;
                this->DebugText("Found Town Center SN: " + to_string(building.SN) + ", Percent: " + to_string(building.Percent) + "%, Current Project: " + to_string(building.Project));
                // If Town Center is fully built and not busy, attempt upgrade
                if (building.Percent == 100 && building.Project == 0) {
                    int ret = BuildingAction(building.SN, BUILDING_CENTER_UPGRADE);
                    if (ret > 0) {
                        this->DebugText("Town Center started age upgrade.");
                    } else {
                        this->DebugText("Town Center age upgrade command failed, error code: " + to_string(ret));
                    }
                    break; // Command issued, exit loop
                } else if (building.Percent < 100) {
                    this->DebugText("Town Center not fully built yet, cannot upgrade age.");
                } else if (building.Project != 0) {
                    this->DebugText("Town Center is busy, cannot upgrade age.");
                }
            }
        }
        if (!townCenterFound) {
            this->DebugText("Town Center not found, cannot upgrade age.");
        }
    } else {
        this->DebugText("Not enough food, need 500 food to upgrade age.");
    }
    // Villager task assignment is handled by processData during upgrade phase
}

// New: Post-Tool Age stage handling (tasks after upgrading to Tool Age)
void UsrAI::afterUpgradePhase(const tagInfo& info) {
    this->DebugText("Post-Tool Age Stage | Villagers to Produce: " + to_string(villagersToProduceAfterUpgrade) +
              " | Villagers Produced: " + to_string(villagersProducedAfterUpgrade) +
              " | Target Total Stocks: " + to_string(TARGET_TOTAL_STOCKS) +
              " | Houses to Build: " + to_string(housesToBuildAfterUpgrade) +
              " | Houses Built: " + to_string(housesBuiltAfterUpgrade));
    this->DebugText("Wood Status: " + to_string(info.Wood) + " | Wood needed for House: " + to_string(BUILD_HOUSE_WOOD));

    // 1. Ensure toolAgeBuilderSN is assigned and valid
    tagFarmer* currentToolAgeBuilder = nullptr;
    if (toolAgeBuilderSN != -1) {
        for (const auto& farmer : info.farmers) {
            if (farmer.SN == toolAgeBuilderSN && farmer.FarmerSort == 0) {
                currentToolAgeBuilder = const_cast<tagFarmer*>(&farmer);
                break;
            }
        }
        if (currentToolAgeBuilder == nullptr) {
            // Builder died or no longer exists, reset for reassignment
            this->DebugText("Tool Age Builder SN " + to_string(toolAgeBuilderSN) + " not found, resetting assignment.");
            toolAgeBuilderAssigned = false;
            toolAgeBuilderSN = -1;
        }
    }

    // Assign a new dedicated builder if none is assigned or the old one is invalid
    if (!toolAgeBuilderAssigned) {
        for (const auto& farmer : info.farmers) {
            if (farmer.NowState == HUMAN_STATE_IDLE &&
                farmer.FarmerSort == 0 && // Ensure it's a land villager
                ordinaryVillagers.count(farmer.SN)) // Must be an ordinary villager
            {
                toolAgeBuilderSN = farmer.SN;
                toolAgeBuilderAssigned = true;
                ordinaryVillagers.erase(toolAgeBuilderSN); // Remove from ordinary villagers
                currentToolAgeBuilder = const_cast<tagFarmer*>(&farmer);
                this->DebugText("Assigned villager #" + to_string(toolAgeBuilderSN) + " as Tool Age Builder.");
                break; // Assign only one builder
            }
        }
    }

    if (toolAgeBuilderAssigned) {
        string state = "Dedicated Builder #" + to_string(toolAgeBuilderSN);
        if (currentToolAgeBuilder) {
            state += " State: " + to_string(currentToolAgeBuilder->NowState);
        } else {
            state += " Not found!";
        }
        this->DebugText(state);
    }


    // 2. Produce villagers (up to 6) from Town Center
    if (villagersProducedAfterUpgrade < villagersToProduceAfterUpgrade) {
        for (const auto& building : info.buildings) {
            if (building.Type == BUILDING_CENTER &&
                building.Percent == 100 &&
                building.Project == 0) // Town Center is fully built and idle
            {
                if (info.Meat >= BUILDING_CENTER_CREATEFARMER_FOOD && // Check food cost
                    (info.farmers.size() + info.armies.size()) < info.Human_MaxNum) // Check population cap
                {
                    int ret = BuildingAction(building.SN, BUILDING_CENTER_CREATEFARMER);
                    if (ret > 0) {
                        villagersProducedAfterUpgrade++;
                        this->DebugText("Tool Age Villager Production: " + to_string(villagersProducedAfterUpgrade) + "/" + to_string(villagersToProduceAfterUpgrade));
                    } else {
                        this->DebugText("Tool Age Villager Production command failed, error code: " + to_string(ret));
                    }
                    return; // Only attempt to produce one villager per frame to avoid spamming commands
                } else {
                    if (info.Meat < BUILDING_CENTER_CREATEFARMER_FOOD) {
                        this->DebugText("Tool Age: Not enough food to produce villagers. Needed: " + to_string(BUILDING_CENTER_CREATEFARMER_FOOD) + ", Owned: " + to_string(info.Meat));
                    }
                    if ((info.farmers.size() + info.armies.size()) >= info.Human_MaxNum) {
                        this->DebugText("Population cap reached, cannot produce more villagers in Tool Age.");
                    }
                }
            }
        }
    }

    // 3. Update current number of houses built (important to do this before attempting to build more)
    int actualHousesBuilt = 0;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_HOME && b.Percent == 100) {
            actualHousesBuilt++;
        }
    }
    housesBuiltAfterUpgrade = actualHousesBuilt; // Update static variable

    // 4. Update Granary and Market status
    granaryBuilt = false;
    marketBuilt = false;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_GRANARY && b.Percent == 100) {
            granaryBuilt = true;
        }
        if (b.Type == BUILDING_MARKET && b.Percent == 100) {
            marketBuilt = true;
        }
    }

    // 5. Dedicated builder tasks: Build Stocks, then Houses, then Granary, then Market
    if (toolAgeBuilderAssigned && currentToolAgeBuilder && currentToolAgeBuilder->NowState == HUMAN_STATE_IDLE) {
        int currentTotalStocks = 0;
        for (const auto& b : info.buildings) {
            if (b.Type == BUILDING_STOCK) {
                currentTotalStocks++;
            }
        }

        if (currentTotalStocks < TARGET_TOTAL_STOCKS) {
            // Build Stock
            int bestX = -1, bestY = -1;
            // Use the new findBestStockPosition function to find a location near trees
            if (this->findBestStockPosition(bestX, bestY, info)) {
                if (info.Wood >= BUILD_STOCK_WOOD) {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " attempting to build Stock at (" + to_string(bestX) + "," + to_string(bestY) + ").");
                    int ret = HumanBuild(toolAgeBuilderSN, BUILDING_STOCK, bestX, bestY);
                    if (ret > 0) {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " successfully started building Stock.");
                        // Mark the 3x3 area as occupied
                        for (int i = 0; i < 3; i++) {
                            for (int j = 0; j < 3; j++) {
                                occupiedPositions.insert({bestX+i, bestY+j});
                            }
                        }
                        return; // Builder is now busy, exit function for this frame
                    } else {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " Stock build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": Not enough wood to build Stock. Needed: " + to_string(BUILD_STOCK_WOOD) + ", Owned: " + to_string(info.Wood));
                }
            } else {
                this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": No suitable location found near trees to build Stock.");
            }
        } else if (housesBuiltAfterUpgrade < housesToBuildAfterUpgrade) {
            // Build Houses
            int buildX, buildY;
            // Find a nearby position for a house (2x2)
            if (this->findNearbyPosition(buildX, buildY, info, 2, 2, BUILDING_HOME)) {
                if (info.Wood >= BUILD_HOUSE_WOOD) {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " attempting to build House at (" + to_string(buildX) + "," + to_string(buildY) + ").");
                    int ret = HumanBuild(toolAgeBuilderSN, BUILDING_HOME, buildX, buildY);
                    if (ret > 0) {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " successfully started building House.");
                        // housesBuiltAfterUpgrade will be updated by full scan at the start of next frame
                        // Mark the 2x2 area as occupied
                        for (int i = 0; i < 2; i++) {
                            for (int j = 0; j < 2; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                        return; // Builder is now busy, exit function for this frame
                    } else {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " House build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": Not enough wood to build House. Needed: " + to_string(BUILD_HOUSE_WOOD) + ", Owned: " + to_string(info.Wood));
                }
            } else {
                this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": No suitable location found to build House.");
            }
        } else if (!granaryBuilt) {
            // Build Granary
            int buildX, buildY;
            // Find a nearby position for a granary (3x3)
            if (this->findNearbyPosition(buildX, buildY, info, 3, 3, BUILDING_GRANARY)) {
                if (info.Wood >= BUILD_GRANARY_WOOD) {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " attempting to build Granary at (" + to_string(buildX) + "," + to_string(buildY) + ").");
                    int ret = HumanBuild(toolAgeBuilderSN, BUILDING_GRANARY, buildX, buildY);
                    if (ret > 0) {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " successfully started building Granary.");
                        // Mark the 3x3 area as occupied
                        for (int i = 0; i < 3; i++) {
                            for (int j = 0; j < 3; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                        return; // Builder is now busy, exit function for this frame
                    } else {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " Granary build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": Not enough wood to build Granary. Needed: " + to_string(BUILD_GRANARY_WOOD) + ", Owned: " + to_string(info.Wood));
                }
            } else {
                this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": No suitable location found to build Granary.");
            }
        } else if (!marketBuilt) {
            // Build Market
            int buildX, buildY;
            // Find a nearby position for a market (3x3)
            if (this->findNearbyPosition(buildX, buildY, info, 3, 3, BUILDING_MARKET)) {
                if (info.Wood >= BUILD_MARKET_WOOD) {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " attempting to build Market at (" + to_string(buildX) + "," + to_string(buildY) + ").");
                    int ret = HumanBuild(toolAgeBuilderSN, BUILDING_MARKET, buildX, buildY);
                    if (ret > 0) {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " successfully started building Market.");
                        // Mark the 3x3 area as occupied
                        for (int i = 0; i < 3; i++) {
                            for (int j = 0; j < 3; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                        return; // Builder is now busy, exit function for this frame
                    } else {
                        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " Market build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": Not enough wood to build Market. Needed: " + to_string(BUILD_MARKET_WOOD) + ", Owned: " + to_string(info.Wood));
                }
            } else {
                this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + ": No suitable location found to build Market.");
            }
        }
    } else if (toolAgeBuilderAssigned && currentToolAgeBuilder && currentToolAgeBuilder->NowState != HUMAN_STATE_IDLE) {
        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " is currently busy. Waiting.");
    } else if (toolAgeBuilderAssigned && !currentToolAgeBuilder) {
        // This case should be handled by initial builder validity check, but as a safeguard
        this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " assigned but not found. Re-evaluating assignment.");
        toolAgeBuilderAssigned = false;
        toolAgeBuilderSN = -1;
    }


    // 6. Assign other idle villagers to chop wood (skip food collection in Tool Age)
    for (const auto& farmer : info.farmers) {
        if (farmer.FarmerSort == 0 &&    // Land villager
            farmer.SN != toolAgeBuilderSN &&  // Not the dedicated builder
            farmer.NowState == HUMAN_STATE_IDLE) // Is idle
        {
            int treeSN = findNearestResource(farmer, RESOURCE_TREE, info, std::unordered_set<int>());
            if (treeSN != -1) {
                HumanAction(farmer.SN, treeSN);
                this->DebugText("Villager #" + to_string(farmer.SN) + " assigned to chop wood in Tool Age.");
            } else {
                this->DebugText("Villager #" + to_string(farmer.SN) + " found no trees, remaining idle.");
            }
        }
    }


    // 7. Check stage completion conditions
    // Removed allNewVillagersProduced from the condition as per user request
    int currentTotalStocks = 0; // Recalculate currentTotalStocks for final check
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_STOCK && b.Percent == 100) { // Only count completed stocks
            currentTotalStocks++;
        }
    }
    bool allNewStocksPlanned = (currentTotalStocks >= TARGET_TOTAL_STOCKS); // This condition now correctly reflects completed stocks

    bool allHousesBuilt = (housesBuiltAfterUpgrade >= housesToBuildAfterUpgrade);
    bool allBuildingsCompleted = granaryBuilt && marketBuilt; // New condition for Granary and Market

    if (allNewStocksPlanned && allHousesBuilt && allBuildingsCompleted) // Modified condition
    {
        this->DebugText("Tool Age tasks (stocks, houses, granary, and market) completed. Releasing builder."); // Updated debug text

        // Release builder back to ordinary villagers
        if (toolAgeBuilderAssigned && ordinaryVillagers.find(toolAgeBuilderSN) == ordinaryVillagers.end()) {
            ordinaryVillagers.insert(toolAgeBuilderSN);
        }
        toolAgeBuilderAssigned = false;
        toolAgeBuilderSN = -1;

        currentStage = STAGE_BUILD_WARSHIPS; // Transition to new warship production stage
    } else {
        // Ensure dedicated builder is not in ordinary set if stage is not complete
        if (toolAgeBuilderAssigned && ordinaryVillagers.count(toolAgeBuilderSN)) {
            ordinaryVillagers.erase(toolAgeBuilderSN);
            this->DebugText("Tool Age Builder #" + to_string(toolAgeBuilderSN) + " is still busy, removed from ordinary villagers set.");
        }
        this->DebugText("Tool Age tasks still in progress. Total Stocks (Completed): " + to_string(currentTotalStocks) + "/" + to_string(TARGET_TOTAL_STOCKS) +
                        ", Houses Built: " + to_string(housesBuiltAfterUpgrade) + "/" + to_string(housesToBuildAfterUpgrade) +
                        ", Granary: " + string(granaryBuilt ? "Completed" : "Pending") +
                        ", Market: " + string(marketBuilt ? "Completed" : "Pending"));
    }
}


// Warship production stage logic
void UsrAI::buildWarshipsPhase(const tagInfo& info) {
    // Update warship count
    warshipCount = 0;
    for (const auto& army : info.armies) {
        if (army.Sort == AT_SHIP) { // AT_SHIP is the constant for warship type
            warshipCount++;
        }
    }

    this->DebugText("Warship Production Stage | Current Warships: " + to_string(warshipCount) + " | Target: " + to_string(TARGET_WARSHIPS));

    // Transition condition: target number of warships reached
    if (warshipCount >= TARGET_WARSHIPS) {
        this->DebugText("=== Warship target quantity reached. All warship production tasks completed ===");
        fleetsFormed = false; // Reset flag to form fleets on first entry to explore phase
        currentStage = STAGE_EXPLORE; // Transition to exploration stage
        this->DebugText("=== Warship production completed, entering Exploration Stage ===");
        return; // Stage changed, exit
    }

    bool productionAttemptedThisFrame = false;
    bool allCompletedDocksAtWarshipCapacity = true;

    // Iterate through all docks to produce warships
    for (const auto& building : info.buildings) {
        if (building.Type == BUILDING_DOCK && building.Percent == 100) { // Only use fully built docks
            // Check if this dock is currently busy with a project
            if (building.Project != 0) {
                this->DebugText("  Dock SN " + to_string(building.SN) + " is busy with project " + to_string(building.Project) + ", cannot produce warships.");
                continue;
            }

            int warshipsProducedByThisDock = dockWarshipCount[building.SN];
            this->DebugText("  Dock SN " + to_string(building.SN) + " Warships Produced: " + to_string(warshipsProducedByThisDock) + " | Target: " + to_string(TARGET_WARSHIPS_PER_DOCK));

            if (warshipsProducedByThisDock < TARGET_WARSHIPS_PER_DOCK) {
                allCompletedDocksAtWarshipCapacity = false; // At least one dock can still produce
                const int BUILD_WARSHIP_WOOD_COST = BUILDING_DOCK_CREATE_SHIP_WOOD; // Use actual constant from AI.h/game

                if (info.Wood >= BUILD_WARSHIP_WOOD_COST) {
                    this->DebugText("  Dock SN " + to_string(building.SN) + " attempting to produce warship...");
                    int ret = BuildingAction(building.SN, BUILDING_DOCK_CREATE_SHIP);
                    productionAttemptedThisFrame = true; // Mark that a production attempt was made

                    if (ret > 0) {
                        this->DebugText("  Dock SN " + to_string(building.SN) + " successfully started producing warship.");
                        dockWarshipCount[building.SN]++; // Track production per dock
                        return; // Only issue one production command per frame to avoid spamming
                    } else {
                        this->DebugText("  Producing warship from Dock SN " + to_string(building.SN) + " failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("  Not enough wood to produce warship (Dock SN " + to_string(building.SN) + "). Needed: " + to_string(BUILD_WARSHIP_WOOD_COST) + ", Owned: " + to_string(info.Wood));
                }
            } else {
                this->DebugText("  Dock SN " + to_string(building.SN) + " has reached its warship production target (" + to_string(TARGET_WARSHIPS_PER_DOCK) + " ships).");
            }
        }
    }

    // If no production was attempted or possible this frame, assign villagers to collect resources
    if (!productionAttemptedThisFrame) {
        this->assignTasksToVillagersWithLimits(info, false);
    }
}

// New: Form warship fleets for exploration/attack
void UsrAI::formWarshipFleets(const tagInfo& info) {
    // Clear existing fleets and assigned warships to rebuild, ensuring only active warships are included
    warshipFleets.clear();
    assignedWarships.clear();
    fleetExplorationTargets.clear(); // Clear targets as fleet indices might change
    fleetAttackTargetsSN.clear(); // Clear attack targets

    std::vector<int> availableWarships;
    for (const auto& army : info.armies) {
        if (army.Sort == AT_SHIP) { // Collect all warships
            availableWarships.push_back(army.SN);
        }
    }

    std::sort(availableWarships.begin(), availableWarships.end()); // Sort to ensure consistent fleet formation

    // Form fleets of TARGET_WARSHIPS_PER_DOCK size
    while (availableWarships.size() >= TARGET_WARSHIPS_PER_DOCK) {
        std::vector<int> newFleet;
        for (int i = 0; i < TARGET_WARSHIPS_PER_DOCK; ++i) {
            newFleet.push_back(availableWarships.back());
            assignedWarships.insert(availableWarships.back()); // Mark as assigned
            availableWarships.pop_back(); // Remove from available list
        }
        warshipFleets.push_back(newFleet);
        this->DebugText("Formed new warship fleet containing warships SN: ");
        for (int sn : newFleet) {
            this->DebugText("  #" + to_string(sn));
        }
    }
    // Any remaining warships (less than TARGET_WARSHIPS_PER_DOCK) will remain unassigned for now.
}

// Exploration stage logic for warships
void UsrAI::explorePhase(const tagInfo& info) {
    this->DebugText("Exploration Stage | Warship Count: " + to_string(warshipCount));

    // === Modification 1: Form fleets only on first entry ===
    if (!fleetsFormed) {
        this->DebugText("首次进入探索阶段，组建舰队");
        formWarshipFleets(info);
        fleetsFormed = true;
    }

    this->DebugText("探索阶段 | 舰队数量: " + to_string(warshipFleets.size()));

    // Iterate through each fleet
    for (size_t i = 0; i < warshipFleets.size(); ++i) {
        const auto& fleet = warshipFleets[i];
        if (fleet.empty()) continue; // Skip empty fleets

        // Find the actual tagArmy object for the fleet leader (first warship in the fleet)
        int fleetLeaderSN = fleet[0];
        const tagArmy* fleetLeader = nullptr;
        for (const auto& army : info.armies) {
            if (army.SN == fleetLeaderSN) {
                fleetLeader = &army;
                break;
            }
        }

        if (fleetLeader == nullptr) {
            this->DebugText("Fleet " + to_string(i) + " leader warship #" + to_string(fleetLeaderSN) + " not found (possibly destroyed), skipping this fleet.");
            continue; // Leader not found, skip this fleet
        }

        // If the leader is busy, check its current task
        if (fleetLeader->NowState != HUMAN_STATE_IDLE) {
            this->DebugText("Fleet " + to_string(i) + " leader warship #" + to_string(fleetLeaderSN) + " is busy. State: " + to_string(fleetLeader->NowState));

            bool isAttackingValidTarget = false;
            if (fleetAttackTargetsSN.count(i)) { // Check if this fleet has an attack target
                int currentAttackTargetSN = fleetAttackTargetsSN[i];
                bool targetExists = false;
                for (const auto& enemyArmy : info.enemy_armies) {
                    if (enemyArmy.SN == currentAttackTargetSN) {
                        targetExists = true;
                        break;
                    }
                    // Also check enemy buildings if applicable for attack targets
                    for (const auto& enemyBuilding : info.enemy_buildings) {
                        if (enemyBuilding.SN == currentAttackTargetSN) {
                            targetExists = true;
                            break;
                        }
                    }
                }
                if (targetExists) {
                    // If the leader is attacking and its target is still valid
                    if (fleetLeader->NowState == HUMAN_STATE_ATTACKING && fleetLeader->WorkObjectSN == currentAttackTargetSN) {
                        isAttackingValidTarget = true;
                        this->DebugText("Fleet " + to_string(i) + " is actively attacking valid target SN " + to_string(currentAttackTargetSN) + ".");
                        continue; // Continue attacking, no new commands needed
                    } else {
                        // Target exists, but leader is not actively attacking it or is pathfinding to it
                        this->DebugText("Fleet " + to_string(i) + "'s attack target SN " + to_string(currentAttackTargetSN) + " exists, but leader is not actively attacking it. Re-issuing attack command.");
                        for (int shipSN : fleet) {
                            HumanAction(shipSN, currentAttackTargetSN); // Re-issue attack command
                        }
                        continue; // Command issued, skip further logic for this fleet
                    }
                } else {
                    // Target does not exist (destroyed or moved away)
                    this->DebugText("Fleet " + to_string(i) + "'s attack target SN " + to_string(currentAttackTargetSN) + " has disappeared, canceling attack task.");
                    fleetAttackTargetsSN.erase(i); // Clear attack target
                    // Cancel current task for all ships (move to current position)
                    for (int shipSN : fleet) {
                        HumanMove(shipSN, fleetLeader->DR, fleetLeader->UR);
                    }
                    // Do NOT continue here, let it fall through to exploration logic to find new task
                }
            } else {
                // Leader is busy but has no attack target, likely pathfinding or returning.
                // Let it fall through to exploration logic to get a new task if idle after current movement.
                this->DebugText("Fleet " + to_string(i) + " leader is busy but has no attack target. Will re-evaluate for exploration.");
                // No 'continue' here, allow it to proceed to exploration logic if it becomes idle or needs a new target.
            }
        }

        // 1. Check for nearby enemies (only if not actively attacking a valid target)
        // This block is now reached if the leader was idle OR if its previous busy task was cancelled/invalidated
        int nearestEnemySN = -1;
        double minEnemyDist = -1;
        const int ATTACK_RANGE = 20; // Warship attack range (from constants, or assumed)

        // Search for enemy armies
        for (const auto& enemyArmy : info.enemy_armies) {
            double dist = sqrt(pow(fleetLeader->BlockDR - enemyArmy.BlockDR, 2) +
                               pow(fleetLeader->BlockUR - enemyArmy.BlockUR, 2));

            if (dist <= ATTACK_RANGE) {
                if (nearestEnemySN == -1 || dist < minEnemyDist) {
                    minEnemyDist = dist;
                    nearestEnemySN = enemyArmy.SN;
                }
            }
        }

        // Search for enemy buildings (e.g., docks, towers on enemy coast)
        for (const auto& enemyBuilding : info.enemy_buildings) {
            // Consider only attackable buildings (e.g., DOCK, ARROWTOWER)
            if (enemyBuilding.Type == BUILDING_DOCK || enemyBuilding.Type == BUILDING_ARROWTOWER) {
                double dist = sqrt(pow(fleetLeader->BlockDR - enemyBuilding.BlockDR, 2) +
                                   pow(fleetLeader->BlockUR - enemyBuilding.BlockUR, 2));

                if (dist <= ATTACK_RANGE) {
                    if (nearestEnemySN == -1 || dist < minEnemyDist) {
                        minEnemyDist = dist;
                        nearestEnemySN = enemyBuilding.SN;
                    }
                }
            }
        }


        if (nearestEnemySN != -1) {
            // Enemy detected, assign attack target
            fleetAttackTargetsSN[i] = nearestEnemySN;
            fleetExplorationTargets.erase(i); // Clear exploration target
            this->DebugText("Fleet " + to_string(i) + " detected enemy SN " + to_string(nearestEnemySN) + " at distance " + to_string(minEnemyDist) + ", starting attack.");
            for (int shipSN : fleet) {
                HumanAction(shipSN, nearestEnemySN); // Command all warships in the fleet to attack
            }
            continue; // Skip exploration for this fleet
        } else {
            // No immediate enemy, or enemy is too far. If an attack target existed, clear it.
            if (fleetAttackTargetsSN.count(i)) {
                this->DebugText("Fleet " + to_string(i) + " enemy disappeared or out of range, resuming exploration.");
                fleetAttackTargetsSN.erase(i);
            }
        }

        // 2. Exploration logic - prioritize unknown areas
        // Only proceed with exploration if the fleet leader is truly idle or its previous task was cancelled and no new enemy was found
        if (fleetLeader->NowState == HUMAN_STATE_IDLE) { // Only send new commands if IDLE
            bool needsNewTarget = (!fleetExplorationTargets.count(i) || // No current target
                (abs(fleetLeader->BlockDR - fleetExplorationTargets[i].first) < 5 && // Or current target is very close
                 abs(fleetLeader->BlockUR - fleetExplorationTargets[i].second) < 5));

            if (needsNewTarget) {
                // Prioritize finding unknown (black) areas on the map
                int targetX = -1;
                int targetY = -1;
                bool foundUnknown = false;
                double minDist = 1e9;

                // Iterate through the entire map to find the closest unknown area
                for (int x_map = 0; x_map < 128; x_map++) {
                    for (int y_map = 0; y_map < 128; y_map++) {
                        if ((*info.theMap)[x_map][y_map].type == MAPPATTERN_UNKNOWN) {
                            double dist = sqrt(pow(x_map - fleetLeader->BlockDR, 2) +
                                               pow(y_map - fleetLeader->BlockUR, 2));
                            if (dist < minDist) {
                                minDist = dist;
                                targetX = x_map;
                                targetY = y_map;
                                foundUnknown = true;
                            }
                        }
                    }
                }

                // If an unknown area is found, set it as the exploration target
                if (foundUnknown) {
                    fleetExplorationTargets[i] = {targetX, targetY};
                    this->DebugText("Fleet " + to_string(i) + " assigned to explore UNKNOWN area at (" + to_string(targetX) + "," + to_string(targetY) + ").");
                }
                // If no unknown areas, select a random ocean area for exploration
                else {
                    this->DebugText("No UNKNOWN areas found, selecting random ocean location.");
                    bool validExploreTargetFound = false;
                    const int MAX_EXPLORE_ATTEMPTS = 20; // Max attempts to find a random ocean block
                    for (int attempt = 0; attempt < MAX_EXPLORE_ATTEMPTS; ++attempt) {
                        targetX = rand() % 128; // Random X between 0 and 127
                        targetY = rand() % 128; // Random Y between 0 and 127

                        // Check if the random position is an ocean block
                        if (this->isOcean((*info.theMap)[targetX][targetY].type)) {
                            validExploreTargetFound = true;
                            break;
                        }
                    }
                    if (validExploreTargetFound) {
                        fleetExplorationTargets[i] = {targetX, targetY};
                        this->DebugText("Fleet " + to_string(i) + " assigned to explore ocean at (" + to_string(targetX) + "," + to_string(targetY) + ").");
                    }
                }
            }

            // Send move command to all ships in the fleet (either new target or existing target)
            if (fleetExplorationTargets.count(i)) {
                for (int shipSN : fleet) {
                    // === Modification 2: Ensure move command only sent to IDLE warships ===
                    // Find the current state of the specific ship
                    const tagArmy* currentShip = nullptr;
                    for (const auto& army : info.armies) {
                        if (army.SN == shipSN) {
                            currentShip = &army;
                            break;
                        }
                    }
                    if (currentShip && currentShip->NowState == HUMAN_STATE_IDLE) {
                        this->DebugText("发送移动指令给战舰 #" + to_string(shipSN) +
                                        " 目标: (" + to_string(fleetExplorationTargets[i].first) +
                                        "," + to_string(fleetExplorationTargets[i].second) + ")");
                        HumanMove(shipSN,
                                  fleetExplorationTargets[i].first * BLOCKSIDELENGTH,
                                  fleetExplorationTargets[i].second * BLOCKSIDELENGTH);
                    } else if (currentShip) {
                        this->DebugText("战舰 #" + to_string(shipSN) + " 状态为 " + to_string(currentShip->NowState) + ", 不发送移动指令.");
                    }
                }
            }
        } else {
            this->DebugText("Fleet " + to_string(i) + " leader is not idle, skipping exploration command for this frame.");
        }
    }

    // Ensure all villagers continue chopping wood (as this is a later game stage)
    this->assignTasksToVillagersWithLimits(info, false);
}


// Fishing boat building stage logic
void UsrAI::buildFishingBoatPhase(const tagInfo& info) {
    // Update fishing boat count
    fishingBoatCount = 0;
    for (const auto& farmer : info.farmers) {
        if (farmer.FarmerSort == 2) { // FarmerSort == 2 means fishing boat
            fishingBoatCount++;
        }
    }

    this->DebugText("Fishing Boat Production Stage | Current Fishing Boats: " + to_string(fishingBoatCount) + " | Target: " + to_string(TARGET_FISHING_BOATS));

    // Transition condition: target number of fishing boats reached
    if (fishingBoatCount >= TARGET_FISHING_BOATS) {
        fishingBoatBuilt = true;
        this->DebugText("=== Fishing boat target quantity reached. All fishing boat production tasks completed ===");
        currentStage = STAGE_UPGRADE_AGE; // Transition to Age Upgrade Stage
        this->DebugText("=== Fishing boat production completed, entering Age Upgrade Stage ===");
        return; // Stage changed, exit
    }

    bool productionAttemptedThisFrame = false;
    bool anyDockAvailableForProduction = false;
    bool allCompletedDocksAtCapacity = true;

    // Iterate through all docks to produce fishing boats
    for (const auto& building : info.buildings) {
        if (building.Type == BUILDING_DOCK && building.Percent == 100) { // Only use fully built docks
            anyDockAvailableForProduction = true;

            int boatsProducedByThisDock = dockFishingBoatCount[building.SN];

            this->DebugText("  Dock SN " + to_string(building.SN) + " Fishing Boats Produced: " + to_string(boatsProducedByThisDock) + " | Target: " + to_string(TARGET_BOATS_PER_DOCK));

            if (boatsProducedByThisDock < TARGET_BOATS_PER_DOCK) {
                allCompletedDocksAtCapacity = false; // At least one dock can still produce
                // If dock is idle and enough wood, attempt to produce a fishing boat
                if (building.Project == 0 && info.Wood >= BUILDING_DOCK_CREATE_SAILING_WOOD) {
                    this->DebugText("  Dock SN " + to_string(building.SN) + " attempting to produce fishing boat...");
                    int ret = BuildingAction(building.SN, BUILDING_DOCK_CREATE_SAILING);
                    productionAttemptedThisFrame = true; // Mark that a production attempt was made

                    if (ret > 0) {
                        this->DebugText("  Dock SN " + to_string(building.SN) + " successfully started producing fishing boat.");
                        dockFishingBoatCount[building.SN]++; // Track production per dock
                        return; // Only issue one production command per frame to avoid spamming
                    } else {
                        this->DebugText("  Producing fishing boat from Dock SN " + to_string(building.SN) + " failed, error code: " + to_string(ret));
                    }
                } else {
                    if (building.Project != 0) {
                        this->DebugText("  Dock SN " + to_string(building.SN) + " is busy, cannot produce fishing boat.");
                    } else if (info.Wood < BUILDING_DOCK_CREATE_SAILING_WOOD) {
                        this->DebugText("  Not enough wood to produce fishing boat (Dock SN " + to_string(building.SN) + "). Needed: " + to_string(BUILDING_DOCK_CREATE_SAILING_WOOD) + ", Owned: " + to_string(info.Wood));
                    }
                }
            } else {
                this->DebugText("  Dock SN " + to_string(building.SN) + " has reached its fishing boat production target (" + to_string(TARGET_BOATS_PER_DOCK) + " boats).");
            }
        }
    }

    // If no production was attempted or possible, and total fishing boats not met, and all existing docks are at capacity,
    // then return to build more docks.
    if (!productionAttemptedThisFrame && fishingBoatCount < TARGET_FISHING_BOATS && allCompletedDocksAtCapacity && completedDocksCount < TARGET_DOCKS_NUM) {
        this->DebugText("=== Existing docks have reached production limit, but total fishing boats not met. Returning to Required Buildings Stage to build more docks ===");
        currentStage = STAGE_BUILD_REQUIRED_BUILDINGS;
        return;
    }

    this->assignTasksToVillagersWithLimits(info, false); // Assign tasks to land villagers
}

// Finds the nearest resource of a specific type for a given farmer
int UsrAI::findNearestResource(const tagFarmer& farmer, int resourceType, const tagInfo& info, const std::unordered_set<int>& excludedSNs) {
    int nearestSN = -1;
    double minDistance = -1;

    for (const auto& res : info.resources) {
        // Check resource type, if it has quantity, and if it's not excluded
        if (res.Type == resourceType && res.Cnt > 0 && excludedSNs.find(res.SN) == excludedSNs.end()) {
            double distance = abs(farmer.BlockDR - res.BlockDR) + abs(farmer.BlockUR - res.BlockUR);

            if (nearestSN == -1 || distance < minDistance) {
                minDistance = distance;
                nearestSN = res.SN;
            }
        }
    }
    return nearestSN;
}

// Produces villagers from the Town Center
void UsrAI::produceVillagers(const tagInfo& info) {
    for (const auto& building : info.buildings) {
        // Find a fully built and idle Town Center
        if (building.Type == BUILDING_CENTER && building.Percent == 100 && building.Project == 0) {
            // Check for sufficient food and population capacity
            if (info.Meat >= 50) {
                if (info.farmers.size() + info.armies.size() < info.Human_MaxNum) {
                    int ret = BuildingAction(building.SN, BUILDING_CENTER_CREATEFARMER);
                    if (ret > 0) {
                        this->DebugText("Town Center started producing villager.");
                        lastVillagerProductionTime = time(nullptr); // Record production time
                    } else {
                        this->DebugText("Villager production command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("Population cap reached, cannot produce more villagers.");
                }
            } else {
                this->DebugText("Not enough food to produce villagers.");
            }
            break; // Only attempt production from one Town Center per frame
        }
    }
}

// Finds a nearby empty position for building a structure
bool UsrAI::findNearbyPosition(int& x, int& y, const tagInfo& info, int width, int height, int buildingType) {
    int startX = center_x;
    int startY = center_y;

    for (int r = 0; r <= MAX_HOUSE_SEARCH_RADIUS; ++r) { // Iterate through increasing search radii
        for (int i = -r; i <= r; ++i) {
            for (int j = -r; j <= r; ++j) {
                // Only check cells on the perimeter of the square search radius (if r > 0)
                if (r > 0 && abs(i) != r && abs(j) != r) continue;

                int checkX = startX + i;
                int checkY = startY + j;

                // Check map bounds
                if (checkX < 0 || checkY < 0 || checkX >= 128 || checkY >= 128)
                    continue;

                // Use the passed buildingType for validation
                if (this->isPositionValidForBuilding(checkX, checkY, width, height, buildingType, info)) {
                    x = checkX;
                    y = checkY;
                    lastHouseX = x; // Store last found house position (can be generalized)
                    lastHouseY = y;
                    this->DebugText("Found build position: (" + to_string(x) + "," + to_string(y) + "), Size: " + to_string(width) + "x" + to_string(height) + ", Type: " + to_string(buildingType) + ", Radius from TC: " + to_string(r));
                    return true;
                }
            }
        }
    }
    this->DebugText("Warning: No suitable build position found within max radius (" + to_string(MAX_HOUSE_SEARCH_RADIUS) + ") from Town Center for " + to_string(buildingType) + " of size " + to_string(width) + "x" + to_string(height) + ".");
    return false;
}

// House building stage logic
void UsrAI::buildHousesPhase(const tagInfo& info) {
    this->DebugText("House Building Stage | Houses Built: " + to_string(houseCount) +
              " | Under Construction: " + to_string(housesUnderConstruction) +
              " | Target: " + to_string(TARGET_HOUSES));
    this->DebugText("House Stage Condition Check: Houses Built (" + to_string(houseCount) + ") == Target Houses (" + to_string(TARGET_HOUSES) + ") && Houses Under Construction (" + to_string(housesUnderConstruction) + ") == 0");

    // Produce villagers if at least one house is built
    if (houseCount >= 1) {
        this->produceVillagers(info);
    }

    // Transition condition: all target houses built and no houses under construction
    if (houseCount == TARGET_HOUSES && housesUnderConstruction == 0) {
        // Preemptively enter Required Buildings Stage if enough wood for dock
        if (completedDocksCount < TARGET_DOCKS_NUM && info.Wood >= BUILD_DOCK_WOOD) {
            this->DebugText("=== All houses built and enough wood, preemptively entering Required Buildings Stage to build docks ===");
            currentStage = STAGE_BUILD_REQUIRED_BUILDINGS;

            // Reassign house builder as dock builder
            if (houseBuilderSN != -1 && dockBuilderSN == -1) {
                dockBuilderSN = houseBuilderSN;
                dockBuilderReserved = true;
                this->DebugText("Assigned villager #" + to_string(dockBuilderSN) + " as dock builder (after all houses built).");
                if (ordinaryVillagers.count(dockBuilderSN)) {
                    ordinaryVillagers.erase(dockBuilderSN);
                    this->DebugText("Removed dock builder #" + to_string(dockBuilderSN) + " from ordinary villagers set.");
                }
            }
        } else {
            this->DebugText("=== All houses built, entering Population Growth Stage ===");
            currentStage = STAGE_POPULATION_GROWTH;
            targetPopulation = 10; // Set target population for next stage

            // Reassign house builder as dock builder if not already done
            if (houseBuilderSN != -1 && dockBuilderSN == -1) {
                dockBuilderSN = houseBuilderSN;
                dockBuilderReserved = true;
                this->DebugText("Assigned villager #" + to_string(dockBuilderSN) + " as dock builder (houses built, entering population growth).");
                if (ordinaryVillagers.count(dockBuilderSN)) {
                    ordinaryVillagers.erase(dockBuilderSN);
                    this->DebugText("Removed dock builder #" + to_string(dockBuilderSN) + " from ordinary villagers set.");
                }
            }
        }
        return; // Stage changed, exit
    }

    // Logic for building houses if target not met
    if (houseCount + housesUnderConstruction < TARGET_HOUSES) {
        int buildX, buildY;
        // Find a nearby valid position for a house (2x2)
        if (this->findNearbyPosition(buildX, buildY, info, 2, 2, BUILDING_HOME)) {
            if (info.Wood >= BUILD_HOUSE_WOOD) { // Check for sufficient wood
                tagFarmer* builder = nullptr;
                // Try to find the designated house builder
                for (const auto& farmer : info.farmers) {
                    if (farmer.SN == houseBuilderSN && farmer.FarmerSort == 0 && farmer.NowState == HUMAN_STATE_IDLE) {
                        builder = const_cast<tagFarmer*>(&farmer);
                        break;
                    }
                }

                // If no designated builder or it was reset, find a new idle villager
                if (builder == nullptr && houseBuilderSN == -1) {
                    for (const auto& farmer : info.farmers) {
                        if (farmer.FarmerSort == 0 && farmer.NowState == HUMAN_STATE_IDLE) {
                            builder = const_cast<tagFarmer*>(&farmer);
                            houseBuilderSN = farmer.SN;
                            this->DebugText("Reassigned villager #" + to_string(houseBuilderSN) + " as house builder.");
                            break;
                        }
                    }
                } else if (builder == nullptr && houseBuilderSN != -1) {
                    this->DebugText("Designated house builder villager #" + to_string(houseBuilderSN) + " is busy, waiting for idle.");
                }


                if (builder != nullptr) {
                    this->DebugText("Attempting to build house at (" + to_string(buildX) + "," + to_string(buildY) + "), villager #" + to_string(builder->SN));
                    int ret = HumanBuild(builder->SN, BUILDING_HOME, buildX, buildY);
                    if (ret > 0) {
                        this->DebugText("Villager #" + to_string(builder->SN) + " house build command successfully issued.");
                        housesUnderConstruction++; // Increment count of houses under construction
                        // Mark the 2x2 area as occupied
                        for (int i = 0; i < 2; i++) {
                            for (int j = 0; j < 2; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                    } else {
                        this->DebugText("Villager #" + to_string(builder->SN) + " house build command failed, error code: " + to_string(ret));
                    }
                } else {
                    this->DebugText("No idle villager available for house construction.");
                }
            } else {
                this->DebugText("Not enough wood, need " + to_string(BUILD_HOUSE_WOOD) + " wood to build house.");
            }
        }
    }

    this->assignTasksToVillagersWithLimits(info, !dockBuilt); // Assign tasks to villagers
}

// Assigns fishing boats to fish resources or sends them to explore
void UsrAI::assignFishingBoatsToFishResources(const tagInfo& info) {
    this->DebugText("Assigning fishing boats to fish resources.");

    for (const auto& farmer : info.farmers) {
        if (farmer.FarmerSort == 2 && farmer.NowState == HUMAN_STATE_IDLE) { // If it's an idle fishing boat
            this->DebugText("Found idle fishing boat SN: " + to_string(farmer.SN));

            int targetFishSN = -1;
            double minDistance = -1;
            std::unordered_set<int> excludedFishResources; // To avoid assigning multiple boats to the same unreachable fish

            // Try to find an available fish resource
            for (const auto& resource : info.resources) {
                if (resource.Type == RESOURCE_FISH && resource.Cnt > 0 && excludedFishResources.find(resource.SN) == excludedFishResources.end()) {
                    double distance = abs(farmer.BlockDR - resource.BlockDR) + abs(farmer.BlockUR - resource.BlockUR);

                    if (targetFishSN == -1 || distance < minDistance) {
                        minDistance = distance;
                        targetFishSN = resource.SN;
                    }
                }
            }

            if (targetFishSN != -1) {
                // If fish resource found, assign the fishing boat to it
                this->DebugText("Attempting to assign fishing boat SN " + to_string(farmer.SN) + " to fish resource SN " + to_string(targetFishSN));
                int ret = HumanAction(farmer.SN, targetFishSN);
                if (ret > 0) {
                    this->DebugText("Fishing boat SN " + to_string(farmer.SN) + " successfully assigned to fish resource SN " + to_string(targetFishSN) + ".");
                } else {
                    this->DebugText("Assigning fishing boat SN " + to_string(farmer.SN) + " to fish resource SN " + to_string(targetFishSN) + " failed, error code: " + to_string(ret));
                    excludedFishResources.insert(targetFishSN); // Exclude this resource for future attempts in this frame
                }
            } else {
                // If no fish resources found, let the fishing boat explore random ocean areas
                this->DebugText("No available fish resources found for fishing boat SN " + to_string(farmer.SN) + ". Starting exploration.");

                int exploreX = -1, exploreY = -1;
                bool validExploreTargetFound = false;
                const int MAX_EXPLORE_ATTEMPTS = 10; // Try a few times to find a valid ocean block

                for (int attempt = 0; attempt < MAX_EXPLORE_ATTEMPTS; ++attempt) {
                    exploreX = rand() % 128; // Random X between 0 and 127
                    exploreY = rand() % 128; // Random Y between 0 and 127

                    // Check if the random position is an ocean block
                    if (this->isOcean((*info.theMap)[exploreX][exploreY].type)) {
                        validExploreTargetFound = true;
                        break;
                    }
                }

                if (validExploreTargetFound) {
                    this->DebugText("Fishing boat SN " + to_string(farmer.SN) + " assigned to explore to (" + to_string(exploreX) + "," + to_string(exploreY) + ").");
                    HumanMove(farmer.SN, exploreX * BLOCKSIDELENGTH, exploreY * BLOCKSIDELENGTH);
                } else {
                    this->DebugText("After " + to_string(MAX_EXPLORE_ATTEMPTS) + " attempts, could not find a valid ocean block for fishing boat SN " + to_string(farmer.SN) + ". Remaining idle.");
                }
            }
        }
    }
}


// Main game loop function, processes game data and manages stages
void UsrAI::processData() {
    tagInfo info = getInfo(); // Get current game information

    // Update house counts
    houseCount = 0;
    housesUnderConstruction = 0;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_HOME) {
            if (b.Percent == 100) houseCount++;
            else housesUnderConstruction++;
        }
    }

    // Update stock and dock status
    stockBuilt = false;
    dockBuilt = false;
    dockConstructionStarted = false; // Reset each frame, set to true if any dock is being built
    totalDocksPresent = 0;
    completedDocksCount = 0;
    for (const auto& b : info.buildings) {
        if (b.Type == BUILDING_STOCK && b.Percent == 100) {
            stockBuilt = true;
        }
        if (b.Type == BUILDING_DOCK) {
            totalDocksPresent++;
            if (b.Percent == 100) {
                dockBuilt = true; // At least one dock completed
                completedDocksCount++;
            }
            if (b.Percent < 100) { // If any dock is under construction
                dockConstructionStarted = true;
            }
        }
    }

    // Update fishing boat count
    fishingBoatCount = 0;
    for (const auto& farmer : info.farmers) {
        if (farmer.FarmerSort == 2) { // FarmerSort == 2 means fishing boat
            fishingBoatCount++;
        }
    }

    // Update warship count and form fleets
    warshipCount = 0;
    for (const auto& army : info.armies) {
        if (army.Sort == AT_SHIP) { // AT_SHIP is the constant for warship type
            warshipCount++;
        }
    }
    // The formWarshipFleets call here is removed as it's now handled conditionally in explorePhase


    // Detect upgrade start (user requested feature)
    if (!upgradeStarted) {
        for (const auto& building : info.buildings) {
            if (building.Type == BUILDING_CENTER &&
                building.Project == BUILDING_CENTER_UPGRADE) { // Check if Town Center is upgrading
                upgradeStarted = true;
                recallVillagers = true; // Set flag to recall villagers
                this->DebugText("=== Detected Town Center started upgrade, recalling all villagers ===");

                // Initialize building queue for post-upgrade tasks (user requested)
                buildingQueue = std::queue<int>();
                buildingQueue.push(BUILDING_STOCK);  // Stock
                buildingQueue.push(BUILDING_HOME); // 1st house
                buildingQueue.push(BUILDING_HOME); // 2nd house
                buildingQueue.push(BUILDING_HOME); // 3rd house
                buildingQueue.push(BUILDING_HOME); // 4th house
                buildingQueue.push(BUILDING_GRANARY); // Granary
                buildingQueue.push(BUILDING_MARKET);   // Market

                housesBuiltDuringUpgrade = 0; // Reset house count for this phase
                upgradeBuilderSN = -1; // Reset dedicated upgrade builder
                break;
            }
        }
    }

    // Handle villager recall and re-assignment during upgrade (user requested)
    if (recallVillagers) {
        // Recall all land villagers: cancel current tasks by moving them to their current position
        for (const auto& farmer : info.farmers) {
            if (farmer.FarmerSort == 0 && farmer.NowState != HUMAN_STATE_IDLE) {
                HumanMove(farmer.SN, farmer.DR, farmer.UR); // Move to current position = cancel task
            }
        }
        recallVillagers = false; // Clear the flag
        this->DebugText("Villager recall complete, starting re-assignment.");
    }

    // Dedicated builder logic during upgrade (user requested)
    if (upgradeStarted && !buildingQueue.empty()) {
        // Assign or find dedicated builder for upgrade tasks
        if (upgradeBuilderSN == -1) {
            for (const auto& farmer : info.farmers) {
                if (farmer.FarmerSort == 0 &&
                    farmer.NowState == HUMAN_STATE_IDLE) {
                    upgradeBuilderSN = farmer.SN;
                    this->DebugText("Assigned villager #" + to_string(upgradeBuilderSN) + " as upgrade builder.");
                    break;
                }
            }
        }

        // Execute building tasks from the queue if builder is idle
        if (upgradeBuilderSN != -1) {
            bool builderIdle = false;
            for (const auto& farmer : info.farmers) {
                if (farmer.SN == upgradeBuilderSN &&
                    farmer.NowState == HUMAN_STATE_IDLE) {
                    builderIdle = true;
                    break;
                }
            }

            if (builderIdle) {
                int buildingType = buildingQueue.front(); // Get the next building type from queue
                int buildX, buildY;

                // Handle Stock building (requires findBestStockPosition)
                if (buildingType == BUILDING_STOCK) {
                    if (findBestStockPosition(buildX, buildY, info)) {
                        int ret = HumanBuild(upgradeBuilderSN, buildingType, buildX, buildY);
                        if (ret > 0) {
                            this->DebugText("Builder #" + to_string(upgradeBuilderSN) +
                                            " started building Stock in dense tree area.");
                             for (int i = 0; i < 3; i++) { // Stock is 3x3
                                for (int j = 0; j < 3; j++) {
                                    occupiedPositions.insert({buildX+i, buildY+j});
                                }
                            }
                            buildingQueue.pop(); // Pop only on successful command
                        } else {
                            this->DebugText("Builder #" + to_string(upgradeBuilderSN) + " Stock build command failed, error code: " + to_string(ret));
                            // If build failed, don't pop, try again next frame with the same task
                        }
                    } else {
                        this->DebugText("Failed to find best Stock position, skipping this build task.");
                        // Don't pop if we couldn't find a position, try again next frame
                    }
                }
                // Handle other buildings (House, Granary, Market)
                else if (findNearbyPosition(buildX, buildY, info, (buildingType == BUILDING_HOME || buildingType == BUILDING_ARROWTOWER ? 2 : 3), (buildingType == BUILDING_HOME || buildingType == BUILDING_ARROWTOWER ? 2 : 3), buildingType)) {
                    int ret = HumanBuild(upgradeBuilderSN, buildingType, buildX, buildY);
                    if (ret > 0) {
                        string buildingName;
                        int buildingWidth, buildingHeight;
                        switch (buildingType) {
                            case BUILDING_HOME: buildingName = "House"; buildingWidth = 2; buildingHeight = 2; break;
                            case BUILDING_GRANARY: buildingName = "Granary"; buildingWidth = 3; buildingHeight = 3; break;
                            case BUILDING_MARKET: buildingName = "Market"; buildingWidth = 3; buildingHeight = 3; break;
                            default: buildingName = "Unknown Building"; buildingWidth = 1; buildingHeight = 1; break;
                        }
                        this->DebugText("Builder #" + to_string(upgradeBuilderSN) +
                                        " started building " + buildingName);

                        // Increment house count if a house was built during upgrade
                        if (buildingType == BUILDING_HOME) {
                            housesBuiltDuringUpgrade++;
                        }
                        // Mark occupied positions
                        for (int i = 0; i < buildingWidth; i++) {
                            for (int j = 0; j < buildingHeight; j++) {
                                occupiedPositions.insert({buildX+i, buildY+j});
                            }
                        }
                        buildingQueue.pop(); // Pop only on successful command
                    } else {
                        this->DebugText("Builder #" + to_string(upgradeBuilderSN) + " build " + to_string(buildingType) + " command failed, error code: " + to_string(ret));
                        // If build failed, don't pop, try again next frame with the same task
                    }
                } else {
                    this->DebugText("Failed to find nearby position to build " + to_string(buildingType) + ", skipping this build task.");
                    // Don't pop if we couldn't find a position, try again next frame
                }
            }
        }
    }

    // Assign other villagers to chop wood during upgrade (user requested)
    if (upgradeStarted) {
        for (const auto& farmer : info.farmers) {
            if (farmer.FarmerSort == 0 && // Land villager
                farmer.SN != upgradeBuilderSN && // Not the dedicated upgrade builder
                farmer.NowState == HUMAN_STATE_IDLE) // Is idle
            {

                int treeSN = findNearestResource(farmer, RESOURCE_TREE, info, std::unordered_set<int>());
                if (treeSN != -1) {
                    HumanAction(farmer.SN, treeSN);
                    this->DebugText("Villager #" + to_string(farmer.SN) + " assigned to chop wood.");
                } else {
                    this->DebugText("Villager #" + to_string(farmer.SN) + " could not find trees, remaining idle.");
                }
            }
        }
    }


    // Check if age upgrade is complete (user requested)
    if (upgradeStarted && info.civilizationStage == CIVILIZATION_TOOLAGE) {
        this->DebugText("=== Age upgrade completed ===");
        upgradeStarted = false; // Reset the flag

        // If there are still unfinished tasks in the queue, continue processing them
        if (!buildingQueue.empty()) {
            this->DebugText("Continuing to complete unfinished build tasks during upgrade.");
            // The dedicated builder logic above will continue to process the queue
        } else {
            upgradeBuilderSN = -1; // Release builder if queue is empty
            this->DebugText("All build tasks during upgrade completed, builder released.");
        }
    }


    this->DebugText("Current Game Stage: " + to_string(currentStage));

    // Main game stage management
    switch(currentStage) {
        case STAGE_INITIAL:
            if (!centerInitialized) this->initializeCenter(info);
            break;

        case STAGE_BUILD_HOUSES:
            this->buildHousesPhase(info);
            break;

        case STAGE_POPULATION_GROWTH:
            this->populationGrowthPhase(info);
            break;

        case STAGE_COLLECT_RESOURCES:
            this->collectResourcesPhase(info);
            break;

        case STAGE_BUILD_REQUIRED_BUILDINGS:
            this->buildRequiredBuildingsPhase(info);
            break;

        case STAGE_UPGRADE_AGE:
            this->upgradeAgePhase(info);
            break;

        case STAGE_BUILD_FISHING_BOAT:
            this->buildFishingBoatPhase(info);
            break;

        case STAGE_AFTER_UPGRADE: // Handle new stage: tasks after upgrading to Tool Age
            // Only run afterUpgradePhase if the upgradeStarted flag is false (meaning age upgrade is complete)
            if (!upgradeStarted) {
                this->afterUpgradePhase(info);
            } else {
                this->DebugText("Still in upgrade period, afterUpgradePhase not executing.");
            }
            break;

        case STAGE_BUILD_WARSHIPS: // Handle new warship production stage
            this->buildWarshipsPhase(info);
            break;

        case STAGE_EXPLORE: // Handle new exploration stage
            this->explorePhase(info);
            break;
    }

    // Assign fishing boats regardless of current stage, as they operate independently
    this->assignFishingBoatsToFishResources(info);

    prevInfo = info; // Store current info for next frame's comparison
}

// New function: Finds the best stock position (near dense tree areas)
bool UsrAI::findBestStockPosition(int& x, int& y, const tagInfo& info) {
    int bestX = -1, bestY = -1;
    int maxTreeCount = -1;
    const int searchRadius = 8; // Search radius around Town Center

    // Collect all tree positions
    std::vector<std::pair<int, int>> treePositions;
    for (const auto& res : info.resources) {
        if (res.Type == RESOURCE_TREE && res.Cnt > 0) {
            treePositions.push_back({res.BlockDR, res.BlockUR});
        }
    }

    // Search for a suitable stock position around the Town Center
    for (int dx = -searchRadius; dx <= searchRadius; dx++) {
        for (int dy = -searchRadius; dy <= searchRadius; dy++) {
            int candidateX = center_x + dx;
            int candidateY = center_y + dy;

            // Skip invalid positions (out of map bounds)
            if (candidateX < 0 || candidateY < 0 ||
                candidateX >= 128 || candidateY >= 128) {
                continue;
            }

            // Check if position is valid for building a stock (Stock is 3x3)
            if (isPositionValidForBuilding(candidateX, candidateY, 3, 3, BUILDING_STOCK, info)) {
                // Calculate number of nearby trees within a certain radius
                int treeCount = 0;
                for (const auto& tree : treePositions) {
                    double distance = sqrt(pow(candidateX - tree.first, 2) +
                                           pow(candidateY - tree.second, 2));
                    if (distance <= 5.0) { // Trees within 5 blocks
                        treeCount++;
                    }
                }

                // Update best position if more trees are found
                if (treeCount > maxTreeCount) {
                    maxTreeCount = treeCount;
                    bestX = candidateX;
                    bestY = candidateY;
                }
            }
        }
    }

    if (bestX != -1 && bestY != -1) {
        x = bestX;
        y = bestY;
        this->DebugText("Found best stock position, nearby trees: " + to_string(maxTreeCount));
        return true;
    }
    this->DebugText("Failed to find best stock position.");
    return false;
}
